如果您想在命名空间或类中声明一个 __autoload 函数,请使用 spl_autoload_register() 函数注册它,它将正常工作。(PHP 5 >= 5.3.0, PHP 7, PHP 8)
出于这些解析规则的目的,以下是一些重要的定义
这是一个没有命名空间分隔符的标识符,例如 Foo
这是一个带有命名空间分隔符的标识符,例如 Foo\Bar
这是一个带有命名空间分隔符,并且以命名空间分隔符开头的标识符,例如 \Foo\Bar。命名空间 \Foo 也是一个完全限定名称。
这是一个以 namespace 开头的标识符,例如 namespace\Foo\Bar。
名称按照以下解析规则解析
\A\B 解析为 A\B。
namespace 替换为当前命名空间的名称。如果名称出现在全局命名空间中,则会删除 namespace\ 前缀。例如,在命名空间 X\Y 内的 namespace\A 解析为 X\Y\A。全局命名空间中的相同名称解析为 A。
A\B\C 作为 C 导入,则名称 C\D\E 将转换为 A\B\C\D\E。
A\B 内的名称 C\D\E 解析为 A\B\C\D\E。
use A\B\C; 之后,诸如 new C() 的用法解析为名称 A\B\C()。类似地,在 use function A\B\foo; 之后,诸如 foo() 的用法解析为名称 A\B\foo。
A\B 内的 new C() 解析为名称 A\B\C。
A\B 中,以下是函数 foo() 调用的解析方式
A\B\foo()。
foo()。
示例 #1 名称解析图示
<?php
namespace A;
use B\D, C\E as F;
// 函数调用
foo(); // 首先尝试调用在 "A" 命名空间中定义的 "foo"
// 然后调用全局函数 "foo"
\foo(); // 调用在全局范围内定义的函数 "foo"
my\foo(); // 调用在 "A\my" 命名空间中定义的函数 "foo"
F(); // 首先尝试调用在 "A" 命名空间中定义的 "F"
// 然后调用全局函数 "F"
// 类引用
new B(); // 创建在 "A" 命名空间中定义的 "B" 类的对象
// 如果未找到,则尝试自动加载类 "A\B"
new D(); // 使用导入规则,创建在 "B" 命名空间中定义的 "D" 类的对象
// 如果未找到,则尝试自动加载类 "B\D"
new F(); // 使用导入规则,创建在 "C" 命名空间中定义的 "E" 类的对象
// 如果未找到,则尝试自动加载类 "C\E"
new \B(); // 创建在全局范围内定义的 "B" 类的对象
// 如果未找到,则尝试自动加载类 "B"
new \D(); // 创建在全局范围内定义的 "D" 类的对象
// 如果未找到,则尝试自动加载类 "D"
new \F(); // 创建在全局范围内定义的 "F" 类的对象
// 如果未找到,则尝试自动加载类 "F"
// 来自另一个命名空间的静态方法/命名空间函数
B\foo(); // 调用 "A\B" 命名空间中的函数 "foo"
B::foo(); // 调用在 "A" 命名空间中定义的 "B" 类的 "foo" 方法
// 如果未找到类 "A\B",则尝试自动加载类 "A\B"
D::foo(); // 使用导入规则,调用在 "B" 命名空间中定义的 "D" 类的 "foo" 方法
// 如果未找到类 "B\D",则尝试自动加载类 "B\D"
\B\foo(); // 调用 "B" 命名空间中的函数 "foo"
\B::foo(); // 调用全局范围内的 "B" 类的 "foo" 方法
// 如果未找到类 "B",则尝试自动加载类 "B"
// 当前命名空间的静态方法/命名空间函数
A\B::foo(); // 调用 "A\A" 命名空间中 "B" 类的 "foo" 方法
// 如果未找到类 "A\A\B",则尝试自动加载类 "A\A\B"
\A\B::foo(); // 调用 "A" 命名空间中 "B" 类的 "foo" 方法
// 如果未找到类 "A\B",则尝试自动加载类 "A\B"
?>此处提到的术语“自动加载”不应与用于自动加载对象的 __autoload 函数混淆。关于 __autoload 和命名空间的解析,我想分享以下经验
->假设您有以下目录结构
- 根目录
| - loader.php
| - ns
| - foo.php
->foo.php
<?php
命名空间 ns;
类 foo
{
公共 $say;
公共函数 __construct()
{
$this->say = "bar";
}
}
?>
-> loader.php
<?php
//全局空间 <--
函数 __autoload($c)
{
require_once $c . ".php";
}
类 foo 扩展 ns\foo // ns\foo在此处加载
{
公共函数 __construct()
{
parent::__construct();
echo "<br />foo" . $this->say;
}
}
$a = new ns\foo(); // ns\foo 也能在此处正常加载 ns/foo.php。
echo $a->say; // 如预期输出 bar。
$b = new foo; // 正确输出 foobar。
?>
如果您保持目录/文件与命名空间/类名一致,则对象__autoload 能够正常工作。
但是……如果您尝试为loader.php指定命名空间,则显然会收到致命错误。
我的示例只有一个级别的目录,但我已经使用非常复杂和更深层次的结构进行了测试。希望大家觉得有用。
干杯!在使用命名空间和(自定义或基本)自动加载结构时;魔术函数__autoload必须定义在全局作用域中,不能在命名空间中,也不能在其他函数或方法中。
<?php
命名空间 Glue {
/**
* 在此类中定义您的自定义结构和算法
* 用于自动加载。
*/
类 Import
{
公共静态函数 load ($classname)
{
echo '正在自动加载类 '.$classname."\n";
require_once $classname.'.php';
}
}
}
/**
* 在全局命名空间中定义函数 __autoload。
*/
命名空间 {
函数 __autoload ($classname)
{
\Glue\Import::load($classname);
}
}
?>提到的文件系统类比在一个重要点上失败了
命名空间解析*仅*在声明时工作。编译器将所有命名空间/类引用固定为绝对路径,就像创建绝对符号链接一样。
您不能期望相对符号链接,它应该在访问期间——在 PHP 运行时进行评估。
换句话说,命名空间像__CLASS__或self::一样在解析时进行评估。*没有*发生的是像static::这样的延迟静态绑定的配套,它在运行时解析为当前类。
所以你不能这样做
命名空间 Alpha;
类 Helper {
公共静态 $Value = "ALPHA";
}
类 Base {
公共静态函数 Write() {
echo Helper::$Value;
}
}
命名空间 Beta;
类 Helper 扩展 \Alpha\Helper {
公共静态 $Value = 'BETA';
}
类 Base 扩展 \Alpha\Base {}
\Beta\Base::Write(); // 应该写入“BETA”,因为这是运行时的执行命名空间上下文。
如果您将write()函数复制到\Beta\Base中,它将按预期工作。此处提到的术语“自动加载”不应与用于自动加载对象的 __autoload 函数混淆。关于 __autoload 和命名空间的解析,我想分享以下经验
->假设您有以下目录结构
- 根目录
| - loader.php
| - ns
| - foo.php
->foo.php
<?php
命名空间 ns;
类 foo
{
公共 $say;
公共函数 __construct()
{
$this->say = "bar";
}
}
?>
-> loader.php
<?php
//全局空间 <--
函数 __autoload($c)
{
require_once $c . ".php";
}
类 foo 扩展 ns\foo // ns\foo在此处加载
{
公共函数 __construct()
{
parent::__construct();
echo "<br />foo" . $this->say;
}
}
$a = new ns\foo(); // ns\foo 也能在此处正常加载 ns/foo.php。
echo $a->say; // 如预期输出 bar。
$b = new foo; // 正确输出 foobar。
?>
如果您保持目录/文件与命名空间/类名一致,则对象__autoload 能够正常工作。
但是……如果您尝试为loader.php指定命名空间,则显然会收到致命错误。
我的示例只有一个级别的目录,但我已经使用非常复杂和更深层次的结构进行了测试。希望大家觉得有用。
干杯!命名空间可能不区分大小写,但自动加载器通常区分大小写。
帮自己一个忙,保持你的大小写与文件名一致,并且不要过度复杂化自动加载器。
像这样就足够了
<?php
命名空间 org\example;
函数 spl_autoload($className)
{
$file = new \SplFileInfo(__DIR__ . substr(strtr("$className.php", '\\', '/'), 11));
$path = $file->getRealPath();
if(empty($path))
{
return false;
}
else
{
return include_once $path;
}
}
\spl_autoload_register('\org\example\spl_autoload');
?>