spl_autoload_register自动加载函数的参数问题。

源码如下:

class ComposerAutoloaderInit
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';//注意这一行。
        }
    }

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInit', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        .
        .
        //省略很多代码
        .
        .

在我调用 ComposerAutoloaderInit::getLoader() 方法的时候,发现 loadClassLoader 中的 if 执行了(有注释的那行)。但是 if 有条件判断 'ComposerAutoloadClassLoader' === $class ,而 spl_autoload_register 注册的时候似乎没有传递 $class 进去。请 $class 是如何定义的?

阅读 3.7k
2 个回答

首先要明确通过 spl_autoload_register 注册的,不是类,也不是类所对应的文件,而是自动加载方法。
那么 spl_autoload_register 的参数就很明确,是需要一个自动加载的方法的。
这个方法,就是代码里的 array('ComposerAutoloaderInit', 'loadClassLoader') 。
而真正需要加载类的时候,PHP 会调用这个方法,即 ComposerAutoloaderInit::loadClassLoader ,带上类名。

理解这个过程的关键,是分清楚注册和调用是两个流程,而这里,调用者并不是你的代码,而是 PHP 本身,所以你自然就看不到如何传入类名的了。

答:是 Zend 引擎层(即 PHP 底层)实现的回调,和参数传入。

解释如下:

了解 spl_autoload_register

spl_autoload_register 做了什么

将函数注册到SPL __autoload函数队列中。如果该队列中的函数尚未激活,则激活它们。

注意:此时并没有调用你所注册的自动加载函数 ComposerAutoloaderInit:: loadClassLoader

__autoload函数队列是什么

__autoload函数队列Zend 内核维护的一个自动 hash 队列。
Zend 中对应的数据结构定义如下:(注意结构体成员:autoload_functions

ZEND_BEGIN_MODULE_GLOBALS(spl)
    char *       autoload_extensions;
    HashTable *  autoload_functions;
    int          autoload_running;
    int          autoload_extensions_len;
    intptr_t     hash_mask_handle;
    intptr_t     hash_mask_handlers;
    int          hash_mask_init;
ZEND_END_MODULE_GLOBALS(spl)

队列中的函数原型:void auto_func_name(string $class_name)

什么时候调用回调函数

首先需要了解,执行 self::$loader = $loader = new \Composer\Autoload\ClassLoader(); 时,发生了什么:
PHP 中,new 一个对象时,首先会在已经引入的文件中搜索匹配对应的命名空间/类名,如果搜索不到,会触发自动加载函数,即一次调用 __autoload函数队列 中所注册的方法,调用时会将需要实例化的 完整命名空间 + 类名传入

推荐问题