如何在自动加载中使用PHP命名空间?

时间:2009-12-02 05:55:14

标签: php autoload

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

  

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

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

这是我的代码:

Class1.php:

<?php

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

?>

test.php的:

<?php

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

use Person\Barnes\David;

$class = new Class1();

?>

13 个答案:

答案 0 :(得分:111)

Class1不在全球范围内。

请参阅下面的工作示例:

<?php

function __autoload($class)
{
    $parts = explode('\\', $class);
    require end($parts) . '.php';
}

use Person\Barnes\David as MyPerson;

$class = new MyPerson\Class1();

编辑(2009-12-14):

为了澄清,我使用“use ... as”是为了简化示例。

替代方案如下:

$class = new Person\Barnes\David\Class1();

use Person\Barnes\David\Class1;

// ...

$class = new Class1();

答案 1 :(得分:25)

正如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)

答案 2 :(得分:17)

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

这意味着,在您的情况下,__autoload功能会收到“Person\Barnes\David\Class1”,而不仅仅是“Class1”。

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

答案 3 :(得分:11)

我这样做:See this GitHub Example

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___
}

答案 4 :(得分:3)

我看到自动加载功能只接收“完整”类名 - 在它之前的所有名称空间 - 在以下两种情况下:

[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();

希望这有帮助。

答案 5 :(得分: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);
    }
});

答案 6 :(得分: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的工作解决方案

Namespace Autoload works under windows, but not on Linux

答案 7 :(得分:1)

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

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;
});

答案 8 :(得分:1)

我最近发现tanerkuc的答案非常有帮助!只是想补充一点,使用62 + strrpos()略快于substr() + explode()

end()

答案 9 :(得分:1)

我会为相对的初学者投入我的两分钱,或者在没有所有理论的情况下想要一个简单的spl_autoload_register()设置: 只需为每个类创建一个php文件,将php文件命名为与您的类名相同,并将您的类文件保存在与您的php文件相同的目录中,然后这将起作用:

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

Google搜索此功能中的各个部分应该回答它是如何工作的。 PS:我使用Linux,这适用于Linux。 Windows人员应该首先测试它。

答案 10 :(得分:1)

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

您需要将类文件放入名为Classes的文件夹中,该文件夹与PHP应用程序的入口点位于同一目录中。如果类使用名称空间,则名称空间将转换为目录结构。与许多其他自动加载器不同,下划线不会转换为目录结构(使用PHP&lt; 5.3伪命名空间以及PHP&gt; = 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 BusinessDeeper classD {}

答案 11 :(得分:1)

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

spl_autoload_register(function($name){
        require_once 'lib/'.str_replace('\\','/',$name).'.php';
    });

答案 12 :(得分: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();
}
?>