PHP Composer 的自动加载

date
Mar 24, 2021
slug
php-composer-autoload
status
Published
tags
PHP
summary
PHP Composer 自动加载原理
type
Post
PHP 的 autoload 机制,可以在使用一个未导入的类时动态加载该类,从而实现延迟加载和管理依赖类文件的目的。
 

一、没有 composer 时 PHP 是怎么做的

__autoload 自动加载器
PHP 中想要使用一个类,必须通过 require (指代 require_once, include_once 等) 的方式在文件开头声明要使用的类。当项目中类较多时,一个个声明加载显然不可行。
在 PHP5 版本,PHP 支持通过 __autoload 定义一个自动加载器,尝试加载未定义的类。 如:
__autoload 函数缺点比较明显:他只能定义一次,这样就会耦合所有依赖的类的自动加载逻辑,统统写到这个方法里,这时候就需要用到 spl_autoload_register 函数了。
 
使用 spl_autoload_register 注册多个自动加载器
spl 是 standard php library 的缩写。spl_autoload_register 最大的特点是支持注册多个自动加载器,这样就能实现将各个类库的自动加载逻辑分开,自己处理自己的加载逻辑。
 

二、PSR 规范

PSR 即 PHP Standards Recommendation 是一个社区组织:https://www.php-fig.org/psr/,声明一系列规范来统一开发风格,减少互不兼容的困扰。规范中的 PSR-4 代表:Autoloading Standard,即自动加载规范。
 
PSR-4
其中规定:一个类的完整类名应该遵循一下规范:
\<命名空间>(\<子命名空间>)*\<类名>,即:
  1. 完整的类名必须要有一个顶级命名空间,被称为 “vendor namespace”;
  1. 完整的类名可以有一个或多个子命名空间;
  1. 完整的类名必须有一个最终的类名;
  1. 完整的类名中任意一部分中的下滑线都是没有特殊含义的;
  1. 完整的类名可以由任意大小写字母组成;
  1. 所有类名都必须是大小写敏感的。
看看例子:
notion image
应用的效果简单来说就是:将命名空间前缀 Namespace Prefix 替换成 Base Directory 目录,并将 \ 替换成 / 。一句话,命名空间可以表明类具体的存放位置。
 

三、Composer 自动加载的过程

结合 spl_auto_register 和 PSR-4 的命名空间规范,可以想象,我们可以通过类的命名空间,来找到具体类的存放位置,然后通过 require 将其加载进来生效,composer 就是这么干的。
接下来我们分两步看 composer 是怎么做的。
 
第一步,建立类的命名空间和类存放位置的映射关系
首先看 vendor 目录下的 autoload.php 文件,所有项目启动必然要先 require 这个文件。
在代码 P0 处,上来先实例化一个 \Composer\Autoload\ClassLoader 类,这个类里面维护了所有命名空间到类具体存放位置的映射关系。
接下来在 P1 处,根据 PHP 版本和运行环境,如是否运行在 HHVM 环境下,来区分如何向 ClassLoader 中载入映射关系。
autoload_static.php 文件中定义的映射关系有三种:
classMap 是完整映射关系,prefixLengthsPsr4 和 prefixDirsPsr4 是当通过完整命名空间找不到时,通过在目标类名后加上 .php 再次寻找用。
到此,建立命名空间到类存放路径的关系已经完成了。
 
第二步,如何找到类并加载
在上面代码中,将 ClassLoader 的 loadClass 方法注册成加载器:
其中 findFile 方法,就是通过类名,去寻找文件实际的位置,如果找到了,就通过 includeFile 将文件加载进来。主要看看 findFile 中的逻辑:
对于类的加载十分简单,直接去 classmap 中取。如果取不到,则将目标类名追加 .php 后缀,去$prefixLengthsPsr4 和 $prefixDirsPsr4 中查找。
 
第三步,如何加载全局函数
还是通过 autoload_static.php 中定义的数据去加载:
至此 composer 自动加载的逻辑基本就过了一遍。
 

四、composer 的 ClassLoader 中的 classMap 是怎么生成出来的?

扫描所有包中的类,然后生成一个 php 文件,例如:getStaticFile 方法
 
PHP官网对类自动加载的说明:https://www.php.net/manual/zh/language.oop5.autoload.php
 
 

© 菜皮 2020 - 2024