PHP Conference Japan 2024

自动加载类

许多编写面向对象应用程序的开发人员为每个类定义创建一个 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.phpMyClass2.php 文件加载 MyClass1MyClass2 类。

<?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";
?>

添加注释

用户贡献的注释 5 条注释

jarret dot minkler at gmail dot com
15 年前
您不应该在自动加载器内部使用 require_once,因为如果找不到类,它就不会尝试通过使用自动加载器来查找它。

只需使用 require(),它在性能方面也会更好,因为它不必检查它是否唯一。
str at maphpia dot com
8 年前
这是我用于 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();
toi]n[enkayt[attaat]gmaal.com
4 年前
在撰写本文时,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 ();
?>
匿名用户
14 年前
值得一提的是,如果您的操作系统区分大小写,则需要使用与源代码中相同的大小写命名文件,例如 MyClass.php 而不是 myclass.php。
kalkamar at web dot de
16 年前
因为静态类没有构造函数,所以我使用这种方法来初始化此类类。
当您第一次使用该类时,将调用函数 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'));
?>
To Top