【问题标题】:autoload and namespaces自动加载和命名空间
【发布时间】:2011-11-19 14:55:44
【问题描述】:

我已经使用 PHP 很长时间了,但现在我开始尝试新的语言功能,例如命名空间。我有一个关于自动加载的问题,我无法在我的网络搜索中找到足够的答案。

假设我在不同的命名空间中有类:

namespace foo\bar\baz;

class Quux
{
}

namespace fred\barney\wilma;

class Betty
{
}

然后假设我有一个自动加载器,它假定命名空间和目录结构之间存在 1:1 映射:

function autoload ($className)
{
    $className = str_replace ('\\', DIRECTORY_SEPERATOR, $className);
    include ($className . 'php');
}

spl_autoload_register ('autoload');

是否在所有情况下都将完全限定的命名空间传递给自动加载器,或者自动加载器是否需要考虑当前正在使用的命名空间?

例如,如果我执行以下操作:

$a = new \foo\bar\baz\Quux;
$b = new \fred\barney\wilma\Betty;

自动加载器应该可以正常工作。

但是如果我执行以下操作呢?

use \foo\bar\baz as FBB;
$a = new Quux;
$b = new \fred\barney\wilma\Betty;

当尝试实例化一个新的 Quux 时,自动加载器是否仍会获得 \foo\bar\baz\Quux 作为类名参数?还是应该得到FBB\Quux,甚至只是Quux?

如果是后者,我可以使用__NAMESPACE__ 或其他类似机制从我的自动加载器中确定该类应该位于的命名空间吗?

【问题讨论】:

  • 那么你尝试的结果是什么?

标签: php namespaces php-5.3 autoload


【解决方案1】:

自动加载器将获得foo\bar\baz\Quux 作为类名参数。

命名空间名称定义
不合格的名称
这是一个标识符 没有命名空间分隔符,例如 Foo

限定名称
这是一个带有命名空间分隔符的标识符,例如 作为 Foo\Bar

完全限定名称
这是一个带有命名空间分隔符的标识符 以命名空间分隔符开头,例如 \Foo\Bar。 namespace\Foo 也是一个完全限定的名称。

规则是:

所有非限定名和限定名(非完全限定名)都是 在编译期间根据当前的导入规则进行翻译。为了 例如,如果命名空间 A\B\C 被导入为 C,则对 C\D\e() 的调用是 翻译成 A\B\C\D\e()。

【讨论】:

  • 对不起,但恐怕我不得不不接受这个答案。当我尝试实际实现一个像这样工作的自动加载器时,我发现它对new /foo/bar/baz () 工作正常,但如果我这样做use /foo/bar; new baz(),我只会将 baz 传递给我的自动加载器。
  • @GordonM 你应该这样做use foo\bar\baz; new baz();。
  • 是的,我刚刚想通了。抱歉,我完全误解了 use 关键字的工作原理。
【解决方案2】:

您将获得一个完全限定的命名空间名称(没有前导反斜杠)。

这也适用于 PHP 中的所有其他动态语言结构和函数:

如果您编写 $obj = new $class,则 $class 必须是完全限定的并且不使用任何已定义的别名。
如果您编写 class_exists($class),则 $class 也必须是完全限定的。
这同样适用于自动加载:它传递的是完全限定名称。

(我知道这个规则的唯一例外是define 函数,它既可以使用完全限定名称定义常量,也可以使用非限定名称,在这种情况下,它将在当前命名空间中定义。)

【讨论】:

    猜你喜欢
    • 2011-08-06
    • 2013-07-19
    • 2015-07-15
    • 2012-05-21
    • 2013-10-24
    • 1970-01-01
    相关资源
    最近更新 更多