composer自动加载个人分析

新建项目

为了便于一步步看,我选择了新建一个空文件夹去安装composer,安装流程有几个要点需要注意

  • 必须在根目录新建一个 composer.json 文件
  • 必须在该文件中加上一个{} 符号,
  • 随后执行 composer install 命令,则会生成 vendor目录和composer.lock文件,表示安装成功

使用composer

使用composer,我们需要在项目中引入 vendor文件中的autoload.php文件,以laravel为例子,在 bootstrap/autoload.php 中就引入了该文件

Composer加载用到的文件

  • autoload_real.php:自动加载功能的引导类。任务是 composer 加载类的初始化(顶级命名空间与文件路径映射初始化)和注册( spl_autoload_register() )。
  • ClassLoader.php:composer 加载类。composer 自动加载功能的核心类。
  • autoload_static.php:顶级命名空间初始化类,用于给核心类初始化顶级命名空间。
  • autoload_classmap.php:自动加载的最简单形式,有完整的命名空间和文件目录的映射;
  • autoload_files.php:用于加载全局函数的文件,存放各个全局函数所在的文件路径名;
  • autoload_namespaces.php:符合 PSR0 标准的自动加载文件,存放着顶级命名空间与文件的映射;
  • autoload_psr4.php:符合 PSR4 标准的自动加载文件,存放着顶级命名空间与文件的映射;

开始分析

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInit51fb7c1c62d9acb50c2786fb3a59fd2c::getLoader();
  • 进入 autoload.php文件,首先看到的是引入自动加载引导文件autoload_real.php,随后调用该类的gitLoader方法,至于为什么有这么奇怪的类名,则是因为该文件是全局加载的,避免重名引起的不便,则有一个Hash值进行修饰。

getLoader

public static function getLoader()
    {
        //经典的单例模式,无需多说
        if (null !== self::$loader) {
            return self::$loader;
        }
        //注册自动加载函数,加载ClassLoader类,并存放在$loader中。
        spl_autoload_register(array('ComposerAutoloaderInit51fb7c1c62d9acb50c2786fb3a59fd2c', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInit51fb7c1c62d9acb50c2786fb3a59fd2c', '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\ComposerStaticInit51fb7c1c62d9acb50c2786fb3a59fd2c::getInitializer($loader));
        } else {
            //注册psr0
            $map = require __DIR__ . '/autoload_namespaces.php';
            foreach ($map as $namespace => $path) {
                $loader->set($namespace, $path);
            }
            //注册psr4
            $map = require __DIR__ . '/autoload_psr4.php';
            foreach ($map as $namespace => $path) {
                $loader->setPsr4($namespace, $path);
            }
            //注册classmap
            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }
        //再次注册自动加载函数
        $loader->register(true);

        return $loader;
    }

加载第三方库

每当我们composer require ****的时候,其实都会往 autoload_psr4.php,autoload_namespace.php,autoload_classmap.php写入对应的目录与命名空间映射,随后每当触发自动加载函数的时候,系统都会搜索该命名空间对应的文件,把它 require 进来。

例如

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Fuel\\Upload\\' => array($vendorDir . '/fuelphp/upload/src'),
);