composer加载机制
入口文件 index.php#
引入 vendor 的 autoload.php 文件
1 | require __DIR__ . '/../vendor/autoload.php'; |
vendor/autoload.php 文件#
引入 composer 的 autoload_real.php 文件,然后调用 getLoader 方法
1 |
|
vendor/composer/autoload_real.php 文件#
该文件包含
ComposerAutoloaderInit558596bf02a1b04254bb0a6c8d3be828 类
和引入文件函数 composerRequire558596bf02a1b04254bb0a6c8d3be828() 。
getLoader方法#
版本检测#
首先引入文件:
1 | require __DIR__ . '/platform_check.php'; |
检查 composer 依赖需要的 php 版本与环境的 php 版本是否一致,如果环境的 php 版本低于要求的版本,则会返回错误信息。
实例化 ClassLoader 类#
使用 spl_autoload_register 注册 loadClassLoader 方法:
1 | public static function loadClassLoader($class) |
loadClassLoader 方法接收一个类名参数,当类名是 Composer\Autoload\ClassLoader 的时候,引入同级目录下的 ClassLoader.php 文件。
实例化 \Composer\Autoload\ClassLoader 类,参数是 vendor 目录的绝对路径,返回一个加载器实例 $loader。
1 | self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); |
使用 spl_autoload_unregister 取消注册 loadClassLoader 方法。
初始化 $loader 实例的属性#
初始化 $loader 实例的属性有: prefixLengthsPsr4,prefixDirsPsr4,fallbackDirsPsr0,classMap 。
根据环境变量的值(如php版本,是否定义HHVM_VERSION常量等)判断是否使用静态加载方式。
若使用静态加载方式,则引入同级目录下的 autoload_static.php 文件,并且使用 call_user_func 方法回调 getInitializer 方法,参数是加载器实例$loader。
autoload_static.php 文件定义了以上几个属性,通过 getInitializer 方法实现 $loader 属性初始化;
若不使用静态加载方式,则分别引入同级目录下的 autoload_namespaces.php,autoload_psr4.php,autoload_classmap.php 文件,再调用 $loader 实例的 set(),setPsr4(),addClassMap() 方法实现 $loader 属性初始化;
注册自动加载函数#
使用 $loader 实例调用 register 方法,注册加载函数,register 方法体下面再说。
引入单文件#
通过读取配置文件,获取单文件映射数组,通过 composerRequire558596bf02a1b04254bb0a6c8d3be828 函数引入单文件。
返回加载器 $loader#
最后返回加载器 $loader 。
vendor/composer/ClassLoader.php 文件#
register 方法#
使用 spl_autoload_register 注册加载器方法 loadClass ,并且添加到函数队列之首。
loadClass 方法#
调用 findFile 方法,通过类名查找类,返回类的绝对路径,然后调用 includeFile 方法,引入文件。
findFile 方法#
findFile 方法使用 $loader 加载器在前面初始化的属性,根据类名查找类的绝对路径,后返回。
属性值#
ClassLoader 类有几个重要的属性。
classMap 属性保存类名与文件绝对路径的映射
1 | public static $classMap = array ( |
prefixLengthsPsr4 和 prefixDirsPsr4 属性保存命名空间与文件相对路径的映射
1 | // 保存命名空间与文件相对路径的映射, |
fallbackDirsPsr0 属性保存 $rootPath/extend/ 目录下的文件
1 | public static $fallbackDirsPsr0 = array ( |
查找 classMap 类映射#
首先查找类名与文件绝对路径的映射,找到则返回文件路径
1 | // class map lookup |
若以上没有匹配到目标类,则继续向下执行。
调用 findFileWithExtension 方法,使用其余3个属性查找文件路径。
findFileWithExtension 方法#
查找匹配的命名空间#
findFileWithExtension 方法的第一个参数是一个类名,通过类名的首字母判断 prefixLengthsPsr4 属性是否存在对应的命名空间。
如果不存在的话,就进入下一个属性 fallbackDirsPsr0 的判断。
如果存在的话,进入一个 while 循环,直到找到第一个存在的文件路径后返回。
1 | // PSR-4 lookup |
while 循环里,首先找到类名里最后一个反斜杠 “" 的位置 $lastPos ,
从第0位到 $lastPos 位截取类名,得到一个字符串 $subPath ,
字符串 $subPath 后拼接一个反斜杠 “",得到一个[可能是的]命名空间 $search ,
prefixDirsPsr4 属性保存命名空间与相对路径的映射,判断 $search 是否存在 prefixDirsPsr4 映射中,
如果存在,则返回一个数组,包含有一个或者多个路径,
从第 $lastPos + 1 位到最后一位截取类名,保留除命中的命名空间外的类名 $pathEnd , $pathEnd 与命名空间映射的相对路径拼接成绝对路径,判断文件路径是否存在,存在则返回文件路径。
目标类在 $rootPath/extend/ 目录#
1 | // PSR-0 fallback dirs |
遍历 fallbackDirsPsr0 属性,与类名拼接成一个路径,文件路径真实存在则返回。