105

当我尝试使用自动加载和命名空间时出现此错误:

致命错误:第 10 行的/usr/local/www/apache22/data/public/php5.3/test.php中找不到类 'Class1'

谁能告诉我我做错了什么?

这是我的代码:

Class1.php:

<?php

namespace Person\Barnes\David
{
    class Class1
    {
        public function __construct()
        {
            echo __CLASS__;
        }
    }
}

?>

测试.php:

<?php

function __autoload($class)
{
    require $class . '.php';
}

use Person\Barnes\David;

$class = new Class1();

?>
4

13 回答 13

122

Class1不在全局范围内。

请注意,这是一个旧答案,自从您无法假设spl_autoload_register()PHP 5.1 中引入的支持(现在很多年前!)以来,事情已经发生了变化。

这些天来,您可能会使用 Composer。在引擎盖下,这将类似于此代码段的内容,以启用类自动加载

spl_autoload_register(function ($class) {
    // Adapt this depending on your directory structure
    $parts = explode('\\', $class);
    include end($parts) . '.php';
});

为了完整起见,这是旧答案:

要加载未在全局范围内定义的类,您需要使用自动加载器。

<?php

// Note that `__autoload()` is removed as of PHP 8 in favour of 
// `spl_autoload_register()`, see above
function __autoload($class)
{
    // Adapt this depending on your directory structure
    $parts = explode('\\', $class);
    require end($parts) . '.php';
}

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

或没有别名:

use Person\Barnes\David\Class1;

$class = new Class1();
于 2009-12-09T01:35:00.977 回答
29

正如提到的 Pascal MARTIN,您应该将 '\' 替换为 DIRECTORY_SEPARATOR,例如:

$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
include($filename);

另外我建议您重新组织目录结构,以使代码更具可读性。这可能是另一种选择:

目录结构:

ProjectRoot
 |- lib

文件:/ProjectRoot/lib/Person/Barnes/David/Class1.php

<?php
namespace Person\Barnes\David
class Class1
{
    public function __construct()
    {
        echo __CLASS__;
    }
}
?>
  • 为您定义的每个命名空间创建子目录。

文件:/ProjectRoot/test.php

define('BASE_PATH', realpath(dirname(__FILE__)));
function my_autoloader($class)
{
    $filename = BASE_PATH . '/lib/' . str_replace('\\', '/', $class) . '.php';
    include($filename);
}
spl_autoload_register('my_autoloader');

use Person\Barnes\David as MyPerson;
$class = new MyPerson\Class1();
  • 我使用 php 5 recomendation 进行自动加载器声明。如果您仍在使用 PHP 4,请将其替换为旧语法:function __autoload($class)
于 2013-05-14T01:01:43.047 回答
19

您的__autoload函数将收到完整的类名,包括命名空间名称。

这意味着,在您的情况下,该__autoload函数将收到“ Person\Barnes\David\Class1”,而不仅仅是“ Class1”。

所以,你必须修改你的自动加载代码,来处理那种“更复杂”的名字;一种经常使用的解决方案是使用每个“级别”命名空间的一个目录来组织您的文件,并且在自动加载时,\将命名空间名称中的 ' '替换为DIRECTORY_SEPARATOR.

于 2009-12-02T06:00:12.103 回答
15

我做这样的事情:参见这个 GitHub 示例

spl_autoload_register('AutoLoader');

function AutoLoader($className)
{
    $file = str_replace('\\',DIRECTORY_SEPARATOR,$className);

    require_once 'classes' . DIRECTORY_SEPARATOR . $file . '.php'; 
    //Make your own path, Might need to use Magics like ___DIR___
}
于 2015-05-31T18:05:04.493 回答
4

我看到在以下两种情况下,自动加载函数只接收“完整”类名——所有命名空间都在它之前:

[a] $a = new The\Full\Namespace\CoolClass();

[b] use The\Full\Namespace as SomeNamespace; (at the top of your source file) followed by $a = new SomeNamespace\CoolClass();

我看到在以下情况下自动加载函数不会收到完整的类名:

[c] use The\Full\Namespace; (at the top of your source file) followed by $a = new CoolClass();

更新: [c] 是一个错误,并且无论如何都不是命名空间的工作方式。我可以报告说,除了 [c],以下两种情况也很有效:

[d] use The\Full\Namespace; (at the top of your source file) followed by $a = new Namespace\CoolClass();

[e] use The\Full\Namespace\CoolClass; (at the top of your source file) followed by $a = new CoolClass();

希望这可以帮助。

于 2013-08-21T16:07:33.340 回答
3

我从Flysystem找到了这颗宝石

spl_autoload_register(function($class) {
    $prefix = 'League\\Flysystem\\';

    if ( ! substr($class, 0, 17) === $prefix) {
        return;
    }

    $class = substr($class, strlen($prefix));
    $location = __DIR__ . 'path/to/flysystem/src/' . str_replace('\\', '/', $class) . '.php';

    if (is_file($location)) {
        require_once($location);
    }
});
于 2015-02-15T20:20:26.750 回答
3

我在一行中使用了这个简单的技巧:

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\\','/',$name).'.php';
    });
于 2018-08-29T06:52:50.363 回答
2

https://thomashunter.name/blog/simple-php-namespace-friendly-autoloader-class/

您需要将类文件放入名为 的文件夹Classes中,该文件夹与 PHP 应用程序的入口点位于同一目录中。如果类使用命名空间,命名空间将被转换为目录结构。

与许多其他自动加载器不同,下划线不会转换为目录结构(将 PHP < 5.3 伪命名空间与 PHP >= 5.3 真实命名空间一起处理是很棘手的)。

<?php
class Autoloader {
    static public function loader($className) {
        $filename = "Classes/" . str_replace("\\", '/', $className) . ".php";
        if (file_exists($filename)) {
            include($filename);
            if (class_exists($className)) {
                return TRUE;
            }
        }
        return FALSE;
    }
}
spl_autoload_register('Autoloader::loader');

您需要将以下代码放入您的主 PHP 脚本(入口点)中:

require_once("Classes/Autoloader.php");

这是一个示例目录布局:

index.php
Classes/
  Autoloader.php
  ClassA.php - class ClassA {}
  ClassB.php - class ClassB {}
  Business/
    ClassC.php - namespace Business; classC {}
    Deeper/
      ClassD.php - namespace Business\Deeper; classD {}
于 2017-10-26T07:33:30.023 回答
1

Using 有一个陷阱,虽然它是迄今为止最快的方法,但它也希望你的所有文件名都是小写的。

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

例如:

包含 SomeSuperClass 类的文件需要命名为 somesuperclass.php,如果您的文件命名为 SomeSuperClass.php 但在 Windows 下没有问题,则使用 Linux 等区分大小写的文件系统时这是一个问题。

在您的代码中使用 __autoload 可能仍然适用于当前版本的 PHP,但预计此功能将在未来被弃用并最终被删除。

那么剩下的选择是:

此版本适用于 PHP 5.3 及更高版本,并允许文件名 SomeSuperClass.php 和 somesuperclass.php。如果您使用 5.3.2 及更高版本,此自动加载器将运行得更快。

<?php

if ( function_exists ( 'stream_resolve_include_path' ) == false ) {
    function stream_resolve_include_path ( $filename ) {
        $paths = explode ( PATH_SEPARATOR, get_include_path () );
        foreach ( $paths as $path ) {
            $path = realpath ( $path . PATH_SEPARATOR . $filename );
            if ( $path ) {
                return $path;
            }
        }
        return false;
    }
}

spl_autoload_register ( function ( $className, $fileExtensions = null ) {
    $className = str_replace ( '_', '/', $className );
    $className = str_replace ( '\\', '/', $className );
    $file = stream_resolve_include_path ( $className . '.php' );
    if ( $file === false ) {
        $file = stream_resolve_include_path ( strtolower ( $className . '.php' ) );
    }
    if ( $file !== false ) {
        include $file;
        return true;
    }
    return false;
});
于 2015-04-08T01:28:52.057 回答
1

有同样的问题,刚刚发现这个:

当您创建与包含类的名称空间匹配的子文件夹结构时,您甚至不必定义自动加载器。

    spl_autoload_extensions(".php"); // comma-separated list
    spl_autoload_register();

它就像一个魅力

更多信息在这里:http ://www.php.net/manual/en/function.spl-autoload-register.php#92514

编辑:由于反斜杠,这会在 Linux 上引起问题...请参阅此处了解 immeëmosol 的工作解决方案

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

于 2014-07-03T13:23:29.843 回答
1

我将为相对初学者或不想要简单的 spl_autoload_register() 设置而无需所有理论的东西投入两分钱:只需为每个类创建一个 php 文件,将该 php 文件命名为与您的类名相同,并保留您的类文件在与您的 php 文件相同的目录中,那么这将起作用:

spl_autoload_register(function ($class_name) {
    require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . $class_name . '.php';
});

谷歌搜索这个函数中的部分应该可以回答它是如何工作的。PS:我使用Linux,这适用于Linux。Windows 的人应该先测试一下。

于 2016-08-22T05:45:38.893 回答
1

我最近发现 tanerkay 的回答很有帮助!只是想补充一点,使用strrpos()+substr()explode()+稍快end()

spl_autoload_register( function( $class ) {
    $pos = strrpos( $class, '\\' );
    include ( $pos === false ? $class : substr( $class, $pos + 1 ) ).'.php';
});
于 2016-08-05T02:18:00.193 回答
0
<?php
spl_autoload_register(function ($classname){
   // for security purpose
   //your class name should match the name of your class "file.php"
   $classname = str_replace("..", "", $classname);
   require_once __DIR__.DIRECTORY_SEPARATOR.("classes/$classname.class.php");
});
try {
  $new = new Class1();
} catch (Exception $e) {
   echo "error = ". $e->getMessage();
}
?>
于 2018-05-17T12:05:53.393 回答