我有一个使用
spl_autoload_register()
注册的自动加载机:
class MyAutoLoader{
public function __construct(){
spl_autoload_register(array($this, 'loader'));
}
public function loader($className){
var_dump($className);
}
}
$al = new MyAutoLoader(); //Register the autoloader
从
var_dump()
来看,自动加载器似乎在很多事情上被调用,比如要插入数据库的数据、参数化 SQL 查询等等:
string 'name' (length=4)
string 'a:2:{s:5:"label";s:4:"Name";s:8:"required";b:1;}' (length=48)
string 'en_US' (length=5)
string 'object' (length=6)
string 'name = ?' (length=8)
这些东西永远不会是类,所以永远不应该使用
new
或 class_exists()
等加载。
在什么情况下/函数调用被称为自动加载器?我想停止自动加载不是被调用的类的“classNames”,因为每个
$className
都使用file_exist()
进行检查,并具有这些数据字符串检查效率很低。
问题已解决。我首先按照 Brad 的建议进行了回溯,并将跟踪转储到文件中(只需添加一个打开文件并附加到其中的小片段)。
显然,痕迹很大,但我选择了我能找到的最简单的一个。顺便说一句,该跟踪恰好是我编写的一个称为数据库 (ORM) 包装器的跟踪,用于包装令人敬畏的 RedBean ORM 库。我转储的结果
$className
也验证了这一点,因为这些字符串是数据正在进入或从数据库中出来。
话虽如此,我有一个
__call()
可以拦截数据库包装器的方法,进行一些处理,将其传递给 RedBean,处理结果,然后将其发送回调用者。
问题:在处理过程中,我正在调用 is_subclass_of() 和 instanceof,这显然会要求自动加载器尝试加载该类(因为我们没有加载任何名为
name =?
的类,也不存在)。
解决方案是在调用
object
和 is_subclass_of()
之前确保我们有一个 instanceof
:if(is_object($someproperty) && is_subclass_of($someproperty))
。
如果
$someproperty
不是对象,则 if
立即短路,并且 instanceof
和 is_subclass_of()
永远不会被调用,这意味着永远不会调用自动加载器。
正如 Brad 所提到的,使用
require_once
将各种内容发送到自动加载器可能会带来巨大的安全风险,同时,使用 file_exists()
多次访问文件系统效率也相当低下。
因此,总而言之,每次使用
instanceof
、is_subclass_of
、其他类类型函数、类存在函数和反射方法时都会调用自动加载器,正如 Charles 在他的回答中指出的那样。
因此,这个故事的寓意是,如果您打算在混合类型变量上使用类类型函数或上述任何函数,请在将其传递给类类型函数之前先检查它。
在什么情况下/函数调用会调用自动加载器?
我意识到,鉴于评论中指出的问题,这基本上已经成为一个“次要”问题,但它仍然值得回答。 通过
(PHP 5.1+)或 PHP 8.0.0 之前(已弃用 PHP 7.2.0)注册的自动加载函数
__autoload()
函数,在且仅在 PHP 需要访问类时调用尚未定义。这是在到处
,它有一个参数告诉 PHP 不要调用任何自动加载器,默认情况下为 true 会触发自动加载器,并且可以设置为 false 来不调用(第二个) class_exists() 的参数。PHP 手册有一个专门用于自动加载的页面
debug_backtrace
或
debug_print_backtrace
来找出自动加载函数到底在哪里被调用。 从技术上讲,只有当脚本引用不存在的类名时,PHP 才应调用它。