Composer自动加载机制学习——File

Composer有4种自动加载方式:file,classmap,psr-0,psr-4。本篇主要讲解file。

首先在网站目录下,新建一个文件名为Controller.php的文件,代码如下:

class Controller
{
    public function test()
    {
        echo "Controller::test\n";
    }
}

原始加载方式

PHP最原始的加载方式,是在PHP文件头部require需要加载的文件。
例如在网站目录下,新建一个index.php,内容如下:

require 'Controller.php'
$c = new Controller();
$c->test();

运行文件将显示结果:Controller::test

使用composer自动加载

composer安装

略。参考:http://www.884358.com/composer/

生成composer.json文件

在网站目录输入如下命令:

composer init

一直回车即可自动生成一个composer.json文件

生成autoload代码

输入如下命令:

composer install

稍等片刻,网站目录就会多出一个vendor文件夹

修改index.php代码

将index.php代码修改为:

<?php
require 'vendor/autoload.php';
$c = new Controller();
$c->test();

运行index.php,得到的结果如下:

提示Controller类找不到,原因就是没有将Controller类加载进来。

FILE自动加载方式

修改composer.json文件,在里面新增一个autoload的key值,在autoload里面有一个名为files的key,值为需要加载的文件路径。

{
    "name": "dedemao/composer_test",
    "authors": [
        {
            "name": "884358",
            "email": "884358@qq.com"
        }
    ],
    "require": {},
    "autoload":{
        "files":["Controller.php"]
    }
}

然后运行命令composer dump-autoload来重新生成autoload配置文件。

然后运行index.php,结果如下:

可以看到结果正常了。

自动加载执行流程分析

index.php第一行首先是引入了vendor/autoload.php文件,打开vendor/autoload.php文件,可以看到程序将要执行composer/autoload_real.php文件中的getLoader函数。getLoader函数代码如下:

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

        spl_autoload_register(array('ComposerAutoloaderInit4d5ff8a105543c170ef7606290bd9ca9', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit4d5ff8a105543c170ef7606290bd9ca9', 'loadClassLoader'));

        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {

            require_once __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInit4d5ff8a105543c170ef7606290bd9ca9::getInitializer($loader));

        } else {

        }

        $loader->register(true);

        if ($useStaticLoader) {
            $includeFiles = Composer\Autoload\ComposerStaticInit4d5ff8a105543c170ef7606290bd9ca9::$files;
        } else {
            $includeFiles = require __DIR__ . '/autoload_files.php';
        }

        foreach ($includeFiles as $fileIdentifier => $file) {
            composerRequire4d5ff8a105543c170ef7606290bd9ca9($fileIdentifier, $file);
        }
        return $loader;
    }

函数首先是判断了自身类的$loader属性是否有内容,如果有则直接返回,否则继续向下执行。
然后通过自动加载函数,将ClassLoader.php文件加载了进来,并new了一个ClassLoader对象放到自身的$loader属性。
紧接着,判断php版本如果大于5.6且不支持HHVM虚拟机则使用autoload_static.php进行静态初始化。(PS:静态初始化只支持PHP5.6以上版本并且不支持HHVM虚拟机)
查看autoload_static.php,可以看到有一个静态的成员变量files,该变量是一个二维数组,存放的是需要自动加载的类文件。数组由一个hash随机数的键和需要加载的类文件的路径值组合,同时还有一个静态方法:getInitializer,可以看到该方法返回的是一个匿名函数。
回到autoload_real.php,下一步是$loader->register(true);注册自动加载函数,打开ClassLoader.php文件,其中register的代码为:

public function register($prepend = false)
{
    spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}

可以看出,一旦类文件找不到时,就会将找不到的类名传递到ClassLoader.php里的loadClass方法中。
再回到autoload_real.php,下一步是将autoload_static.php中的静态的成员变量files赋值到变量$includeFiles,接着通过循环遍历$includeFiles,依次将$includeFiles数组中的存放的文件路径require进来。
整个加载流程结束。

结论

通过分析autoload的执行流程可以看出,如果在composer.json文件中定义了files方式的自动加载,files里面指定的文件路径会在一开始就require进来,而不是按需加载的。

扩展资料

PHP自定加载原理:http://www.884358.com/php-autoload/

发表评论

邮箱地址不会被公开。 必填项已用*标注