composer的自动加载机制解读
按照composer文档的说法,如果是composer项目,只需要在开始的时候require 'vendor/autoload.php'
即可享受类的自动加载特性。可是这是如何实现的呢?
vendor/autoload.php
以Laravel 5.1项目为例,vendor/autoload.php
文件只做了两件事情:
- include
vendor/composer/autoload_real.php
- 调用
ComposerAutoloaderInitb6d254015e39cf5090fb84fdb1ed664b::getLoader()
vendor/composer/autoload_real.php
仅仅定义了ComposerAutoloaderInitb6d254015e39cf5090fb84fdb1ed664b
类和composerRequireb6d254015e39cf5090fb84fdb1ed664b
函数。(b6d254015e39cf5090fb84fdb1ed664b
应该是类似id一样的东西,确保每次不同) 接下来我们关注下ComposerAutoloaderInitb6d254015e39cf5090fb84fdb1ed664b::getLoader()
做了哪些事情。
ComposerAutoloaderInit<id>::getLoader()
首先,这个类的loader只会初始化一次,第二次是直接返回已经存在的loader了:
1 | if (null !== self::$loader) { |
如果是第一次调用,先注册['ComposerAutoloaderInitb6d254015e39cf5090fb84fdb1ed664b', 'loadClassLoader']
,然后new一个\Composer\Autoload\ClassLoader 作为loader
,然后立马取消注册loadClassLoader
。 接下来就一步一步处理各种autoload了。
autoload_namespaces.php
直接从vendor/composer/autoload_namespaces.php
中返回的就是$namespace
到$path
的一个数组。通过\Composer\Autoload\ClassLoader::set
方法来记录这些信息:
1 | if (!$prefix) { |
autoload_psr4.php
直接从该文件的返回值是$namespace
到$path
的数组。通过\Composer\Autoload\ClassLoader::setPsr4
来记录此信息:
1 | if (!$prefix) { |
autoload_classmap.php
直接从该文件的返回值是$classname
到$path
的数组。通过\Composer\Autoload\ClassLoader::addClassMap
来记录此信息:
1 | if ($this->classMap) { |
这些都处理完之后,\Composer\Autoload\ClassLoader::register
将[$this, 'loadClass']
注册为autoload函数(通过spl_autoload_register
)。
autoload_files.php
直接从该文件的返回值是$fileIdentifier
到文件路径的映射,通过之前定义的composerRequireb6d254015e39cf5090fb84fdb1ed664b
函数来require每个文件。 这个函数在require文件的时候同时也设置了$GLOBALS['__composer_autoload_files'][$fileIdentifier]
的值为true。
\Composer\Autoload\ClassLoader::loadClass
这个函数的作用是装载一个类。
1 | if ($file = $this->findFile($class)) { |
\Composer\Autoload\ClassLoader::findFile
这个函数是composer装载类的重点。
- 首先是从
classMap
里面找$class
对应的文件,如果有,直接返回。 - 然后从
prefixDirsPsr4
找到前缀符合的文件,如果找到,直接返回。(那个prefixLengthsPsr4
就是用来判断需要从$class
去掉的前缀长度) - 接下来,直接从
fallbackDirsPsr4
对应的目录中查找文件。 - PSR-0加载
- namespaced class name变换规则:
\A_namespace\a_class=>/A_namespace/a/class.php
- PEAR-like class name变换规则:
\A_namespace\a_class=>/A/namespace/a/class.php
prefixesPsr0
中查找(和prefixDirsPsr4
类似),直接找到对应的文件,返回。 - namespaced class name变换规则:
- 如果没有,直接从
fallbackDirsPsr0
中尝试加载。
composer的自动加载机制解读