Composer 自动加载的原理
当 PHP 引擎试图实例化未知类的操作时,就会调用
__autoload()
,并将类名当做字符串传递给它。但__autoload()
有个缺点,就是 一个进程中只能定义一次。它是全局唯一的,如果框架占了这个名字,便会导致框架的用户用不了其它的__autoload()
了,包括用户自定义的和其它类库带的。这时候就可以使用spl_autoload_register()
函数。它可以把函数注册到__autoload
队列中。
Version
Composer version 1.5.1
原理
以 Laravel 项目为例,composer.json
文件:
1 | { |
当我们执行
1 | composer dump-autoload |
文件 /vendor/composer/autoload_clasmap.php
会把类名和绝对地址做个映射,返回一个 类名 => 文件地址 这种对应关系的数组。
1 | $vendorDir = dirname(dirname(__FILE__)); |
首页 index.php
调用 composer 的 autoload 文件
1 | require '../vendor/autoload.php'; |
会调用 ComposerAutoloaderInit
类的静态方法 getLoader()
1 | require_once __DIR__ . '/composer' . '/autoload_real.php'; |
verdor/composer/ 目录下有四个配置文件:
- autoload_classmap.php 要加载的class映射
- autoload_files.php 要加载的文件
- autoload_namespaces.php psr-0标准
- psr4.php psr-4标准
getLoader()
这个方法会先把这些配置文件放到 ClassLoader
的私有属性中。
然后通过 $loader->register(true)
来调用 spl_autoload_register()
1 | public function register($prepend = false) |
spl_autoload_register()
把 loadClass()
方法注册到了 autoload 队列中,然后当PHP引擎试图实例化未知类的操作时,就会根据类名和命名空间加载这个类文件。
1 | public function loadClass($class) |
classmap
1 | { |
classmap 做的是类名和文件所在位置的映射
PSR-0 与 PSR-4 的不同
PSR-4 中,在类名中使用下划线没有任何特殊含义。而 PSR-0 则规定类名中的下划线_会被转化成目录分隔符。
PSR-0
1 | { |
PSR-0 有此配置,那么会去寻找 src/Foo/Bar/Baz.php
PSR-0 当试图自动加载 Foo\A_B
这个class时,会去寻找 src/Foo/A/B.php
这个文件。
PSR-4
1 | { |
按照 PSR-4 的规则,当试图自动加载 Foo\Bar\Baz
这个 class 时,会去寻找 src/Bar/Baz.php
这个文件,如果它存在则进行加载。
总结
- composer 的 PSR-4 带来更简洁的文件结构
- 命名空间前缀对应相应的文件夹
- 类名和文件名相同,文件后缀为 PHP