命名空间和自动加载
从技术上讲,自动加载通过在需要 PHP 类但未找到时执行回调来工作。这种回调通常会尝试加载这些类。
通常,自动加载可以理解为在需要类时根据类的完全限定名称(FQN)从适当的路径加载 PHP 文件(特别是 PHP 类文件,其中 PHP 源文件专用于特定类)的尝试。
假设我们有这些类:
application\controllers\Base
的类文件:
<?php
namespace application\controllers { class Base {...} }
application\controllers\Control
的类文件:
<?php
namespace application\controllers { class Control {...} }
application\models\Page
的类文件:
<?php
namespace application\models { class Page {...} }
在源文件夹下,这些类应分别作为其 FQN 放在路径中:
- 源文件夹
applications
controllers
Base.php
Control.php
models
Page.php
使用此函数,此方法可以根据 FQN 以编程方式解析类文件路径:
function getClassPath(string $sourceFolder, string $className, string $extension = ".php") {
return $sourceFolder . "/" . str_replace("\\", "/", $className) . $extension; // note that "/" works as a directory separator even on Windows
}
spl_autoload_register
函数允许我们在需要时使用用户定义的函数加载类:
const SOURCE_FOLDER = __DIR__ . "/src";
spl_autoload_register(function (string $className) {
$file = getClassPath(SOURCE_FOLDER, $className);
if (is_readable($file)) require_once $file;
});
此函数可以进一步扩展为使用后台加载方法:
const SOURCE_FOLDERS = [__DIR__ . "/src", "/root/src"]);
spl_autoload_register(function (string $className) {
foreach(SOURCE_FOLDERS as $folder) {
$extensions = [
// do we have src/Foo/Bar.php5_int64?
".php" . PHP_MAJOR_VERSION . "_int" . (PHP_INT_SIZE * 8),
// do we have src/Foo/Bar.php7?
".php" . PHP_MAJOR_VERSION,
// do we have src/Foo/Bar.php_int64?
".php" . "_int" . (PHP_INT_SIZE * 8),
// do we have src/Foo/Bar.phps?
".phps"
// do we have src/Foo/Bar.php?
".php"
];
foreach($extensions as $ext) {
$path = getClassPath($folder, $className, $extension);
if(is_readable($path)) return $path;
}
}
});
请注意,只要加载使用此类的文件,PHP 就不会尝试加载类。它可以在脚本中间加载,甚至可以在关闭函数中加载。这是开发人员(尤其是使用自动加载的开发人员)应该避免在运行时替换执行源文件的原因之一,尤其是在 phar 文件中。