命名空间自动加载在 windows 下有效,但在 Linux 上无效

Posted

技术标签:

【中文标题】命名空间自动加载在 windows 下有效,但在 Linux 上无效【英文标题】:Namespace Autoload works under windows, but not on Linux 【发布时间】:2011-02-21 04:08:06 【问题描述】:

我有以下 php 代码:

index.php

<?php
spl_autoload_extensions(".php");
spl_autoload_register();

use modules\standard as std;

$handler = new std\handler();
$handler->delegate();
?>

模块\标准\handler.php

<?php
namespace modules\standard 
    class handler 
        function delegate()
            echo 'Hello from delegation!';
        
    

?>

在 Windows 7 下,运行 WAMP,代码会生成消息“Hello from Delegation!”但是在 Linux 下,我得到以下信息:

致命错误:spl_autoload(): Class modules\standard\handler could not be loaded in /var/www/index.php on line 15

Windows 在 WAMP 下运行 PHP 5.3.0,Linux 在 Ubuntu 9.10 下运行 5.3.2 dotdeb 包。

这是我的 linux 机器上的配置问题,还是只是在不同操作系统上处理命名空间和自动加载的方式不同

【问题讨论】:

不是这种情况,但是 spl_autoload-register() 将类名转换为小写,所以如果你使用驼峰命名法(bugs.php.net/bug.php?id=53065),它会在 Unix 上中断 【参考方案1】:

SPL 自动加载器非常原始 - 它不知道命名空间,因此它会尝试加载名称中带有 \ 的文件,而在 Linux/Unix 上,路径分隔符是 / 不是。

【讨论】:

感谢您的提醒。愚蠢的PHP。我要么使用 __autoload() 要么自己做点什么。【参考方案2】:

Herman Radtke 说他已经提交了一个补丁:

http://www.hermanradtke.com/blog/hidden-features-with-spl_autoload-and-namespaces/

:s

我希望它会尽快实施。

现在我使用这个解决方法:

<?php
set_include_path( './classes/' . PATH_SEPARATOR . get_include_path() );
spl_autoload_extensions( '.php , .class.php' );
spl_autoload_register();
function linux_namespaces_autoload ( $class_name )
    
        /* use if you need to lowercase first char *
        $class_name  =  implode( DIRECTORY_SEPARATOR , array_map( 'lcfirst' , explode( '\\' , $class_name ) ) );/* else just use the following : */
        $class_name  =  implode( DIRECTORY_SEPARATOR , explode( '\\' , $class_name ) );
        static $extensions  =  array();
        if ( empty($extensions ) )
            
                $extensions  =  array_map( 'trim' , explode( ',' , spl_autoload_extensions() ) );
            
        static $include_paths  =  array();
        if ( empty( $include_paths ) )
            
                $include_paths  =  explode( PATH_SEPARATOR , get_include_path() );
            
        foreach ( $include_paths as $path )
            
                $path .=  ( DIRECTORY_SEPARATOR !== $path[ strlen( $path ) - 1 ] ) ? DIRECTORY_SEPARATOR : '';
                foreach ( $extensions as $extension )
                    
                        $file  =  $path . $class_name . $extension;
                        if ( file_exists( $file ) && is_readable( $file ) )
                            
                                require $file;
                                return;
                            
                    
            
        throw new Exception( _( 'class ' . $class_name . ' could not be found.' ) );
    
spl_autoload_register( 'linux_namespaces_autoload' , TRUE , FALSE );
?>

【讨论】:

【参考方案3】:
function __autoload($class_name) 
$paths[] = dirname(__FILE__) . "/../libs/misc/";
$paths[] = dirname(__FILE__) . "/../../libs/misc/";
$paths[] = dirname(__FILE__) . "/../../libs/helpers/";
$paths[] = dirname(__FILE__) . "/../../libs/simpleimage/";

foreach($paths as $path)
    
        if(file_exists($path.strtolower($class_name).'.class.php'))
        require_once($path.strtolower($class_name).'.class.php');
        
    

【讨论】:

【参考方案4】:
function __autoload($class_name)

    $class_name = strtolower(str_replace('\\', DIRECTORY_SEPARATOR, $class_name));

    include $class_name . '.php';

在 Apache 上需要 srttolower,因为它(与 IIS 相反)区分大小写。

【讨论】:

【参考方案5】:

这是自动加载时常见的问题。解决方法是在自动加载函数中使用 DIRECTORY_SEPARATOR 常量。

所以你的自动加载功能将如下所示

<?php

spl_autoload_register(function($className) 

    $className = str_replace("\", DIRECTORY_SEPARATOR, $className);
    include_once $_SERVER['DOCUMENT_ROOT'] . '/class/' . $className . '.php';

);

如果您需要了解有关命名空间/类自动加载的更多信息,请访问 here

谢谢。

【讨论】:

以上是关于命名空间自动加载在 windows 下有效,但在 Linux 上无效的主要内容,如果未能解决你的问题,请参考以下文章

命名空间Autoload在Windows下运行,但在Linux上运行

使用命名空间和自动加载器找不到类

使用命名空间自动加载 Composer 和 PSR-0 类

PHP 命名空间与自动加载机制

thinkphp 5.0 命名空间

thinkphp5.0命名空间