您不应该在自动加载器中使用 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 ...
*/
?>
您不应该在自动加载器中使用 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'));
?>
使用 spl_autoload_register() 或 spl_autoload() 自动加载类是安全编码用于 API 集成的最佳和最现代的方式。
它限制了使用“polyfill”或框架所面临的各种攻击,这些框架容易受到数据注入的影响。低级攻击、polyfill 和框架漏洞是一些使用主机编程语言核心功能的有限的利用方式。
您的漏洞和目标端点与开发人员的编程经验相去甚远——不暴露针对您的编程语言及其安全协议的威胁。
每次您将数据从一个程序传输到另一个程序时,都会暴露另一个威胁和另一个攻击端点。当您处于生产环境时,此时 Composer 和其他收集特定安全集成要求的工具应该限制其使用,例如 PCI-DSS、HIPAA 或 GDPR。
使用框架或 polyfill 会让攻击者了解函数何时访问内存以生成预期结果的提示。访问 L1 缓存终端故障(使用机器语言访问内存并读取实际发生情况的攻击)将包含有关正在进行的流程及其时间的所有详细信息。
更不用说,当产品是开源的时,代码是可编辑的,并且易于编译。使用对机器级集成的访问,简单的 10 秒处理时间损失可能会推断出整个应用程序都经历了彻底改造。
为了阻止这种情况,并确保最大限度地提高安全性,让您省心省钱。编程语言的嵌入资源应最大限度地利用,以防止多个端点的彻底改造。正在使用的系统不可删除,也不易移动、删除或更改。