您不应该在自动加载器内部使用 require_once,因为如果找不到类,它就不会尝试通过使用自动加载器来查找它。
只需使用 require(),它在性能方面也会更好,因为它不必检查它是否唯一。
许多编写面向对象应用程序的开发人员为每个类定义创建一个 PHP 源文件。其中一个最大的烦恼是在每个脚本的开头编写很长的包含列表(每个类一个)。
spl_autoload_register() 函数注册任意数量的自动加载器,允许在当前未定义类和接口时自动加载它们。通过注册自动加载器,PHP 将获得最后一次机会加载类或接口,然后再失败并报错。
任何类似类的构造都可以以相同的方式自动加载。这包括类、接口、trait 和枚举。
在 PHP 8.0.0 之前,可以使用 __autoload() 自动加载类和接口。但是,它是 spl_autoload_register() 的一个不太灵活的替代方案,并且 __autoload() 从 PHP 7.2.0 开始已弃用,从 PHP 8.0.0 开始移除。
提示:
spl_autoload_register() 可以被多次调用以注册多个自动加载器。但是,从自动加载函数中抛出异常将中断该过程,并且不允许进一步的自动加载函数运行。因此,强烈建议不要从自动加载函数中抛出异常。
示例 #1 自动加载示例
此示例尝试分别从 MyClass1.php 和 MyClass2.php 文件加载 MyClass1
和 MyClass2
类。
<?php
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
示例 #2 自动加载其他示例
此示例尝试加载 ITest
接口。
<?php
spl_autoload_register(function ($name) {
var_dump($name);
});
class Foo implements ITest {
}
/*
string(5) "ITest"
Fatal error: Interface 'ITest' not found in ...
*/
?>
示例 #3 使用 Composer 的自动加载器
» Composer 生成一个 vendor/autoload.php
,该文件被设置为自动加载由 Composer 管理的包。通过包含此文件,可以无需任何额外操作即可使用这些包。
<?php
require __DIR__ . '/vendor/autoload.php';
$uuid = new Ramsey\Uuid\Uuid::uuid7();
echo "Generated new UUID -> ", $uuid->toString(), "\n";
?>
您不应该在自动加载器内部使用 require_once,因为如果找不到类,它就不会尝试通过使用自动加载器来查找它。
只需使用 require(),它在性能方面也会更好,因为它不必检查它是否唯一。
这是我用于 PSR-4 类的自动加载器。我更喜欢使用 composer 的自动加载器,但这适用于无法使用 composer 的遗留项目。
<?php
/**
* 简单自动加载器,因此我们不需要 Composer 仅用于此。
*/
class Autoloader
{
public static function register()
{
spl_autoload_register(function ($class) {
$file = str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
if (file_exists($file)) {
require $file;
return true;
}
return false;
});
}
}
Autoloader::register();
在撰写本文时,PHP 不支持自动加载普通函数。但是,有一种简单的方法可以欺骗自动加载器来执行此操作。唯一需要的是自动加载器从它遍历的文件中找到搜索的类(或任何其他可自动加载的代码段),并且整个文件将被包含到运行时。
假设您有一个命名空间文件,用于包含您希望自动加载的函数。只需向该文件添加一个同名的类,并使用单个常量属性就足以触发自动加载器搜索该文件。然后可以通过访问常量属性来触发自动加载。
常量可以用任何静态属性或方法或默认构造函数替换。但是,我个人认为名为“load”的常量既优雅又信息丰富。毕竟这是一种变通方法。需要记住的另一件事是,这会在运行时引入一个不必要的类。这样做的好处是不需要手动包含或按路径需要包含包含函数的文件,这反过来使代码维护更容易。这种行为使更改项目结构变得更容易,因为不需要修复手动包含。只需要自动加载器能够找到已移动的文件,这可以自动化。
包含函数的代码文件。
/Some/Namespace/Functions.php
<?php
namespace Some\Namespace;
class Functions { const load = 1; }
function a () {
}
function b () {
}
?>
触发包含函数的文件的自动加载。
main.php
<?php
\Some\Namespace\Functions::load;
a ();
b ();
?>
因为静态类没有构造函数,所以我使用这种方法来初始化此类类。
当您第一次使用该类时,将调用函数 init(如果可用)。
在使用该类之前,不能包含该类,否则 init 函数将不会被调用,因为没有使用自动加载。
<?php
function __autoload($class_name)
{
require_once(CLASSES_PATH.$class_name.'.cls.php');
if(method_exists($class_name,'init'))
call_user_func(array($class_name,'init'));
return true;
}
?>
例如,我使用它根据需要建立 mysql 连接。
也可以通过在函数中添加以下几行来添加析构函数
<?php
if(method_exists($class_name,'destruct'))
register_shutdown_function(array($class_name,'destruct'));
?>