我有一个使用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
Run Code Online (Sandbox Code Playgroud)
从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)
Run Code Online (Sandbox Code Playgroud)
这些东西永远不会是类,所以永远不应该使用new或class_exists()等等.
在什么情况下/函数调用是自动加载器调用?我想停止自动加载不是被调用类的"classNames",因为每个$className都被使用检查file_exist(),并且检查这些数据字符串是非常低效的.
问题解决了.我首先按照Brad的建议进行了回溯,并将跟踪转储到文件中(只需添加一个打开文件并附加到其上的小片段).
显然,痕迹非常大,但我选择了我能找到的最简单的一条.顺便说一下,这个跟踪碰巧是一个调用我编写的数据库(ORM)包装器来包装真棒RedBean ORM库的.我转储的结果$className也验证了,因为这些字符串是数据进出数据库.
话虽如此,我有一个__call()拦截我的数据库包装器的方法,做一些处理,将它传递给RedBean,处理结果,然后将其发送回调用者.
问题:在处理过程中,我正在调用is_subclass_of()和instanceof,这显然会要求自动加载器尝试加载类(因为我们没有任何名为name =?loaded的类,也不存在).
解决方案是实际确保我们有一个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其他类类型的功能,阶级存在的功能和反射法,查尔斯在他的回答示意.
因此,故事的寓意是,如果您计划在混合类型的变量上使用类类型函数或上述任何函数,请在将其传递给类类型函数之前先检查它.
\n\n在什么情况/函数调用下调用自动加载器?
\n
我意识到这基本上已经成为次要的问题,但仍然值得回答。
\n通过spl_autoload_register(PHP 5.1+) 或 PHP 8.0.0 之前注册的自动加载函数(已弃用 PHP 7.2.0)__autoload()函数之前注册的自动加载函数,在 \xe2\x80\x94 时调用,并且仅当 \xe2\x80\x94 PHP 需要访问以下类时调用尚未定义。
除了少数例外,这种做法随处可见,例如class_exists,它有一个参数告诉 PHP 不要调用任何自动加载器,默认情况下为 true 会触发自动加载器,并且可以设置为 false 来不调用(class_exists() 的第二个参数)。
PHP 手册有一个专门用于自动加载的页面。如果有任何困惑,我建议您查看一下。
\n