composer包的自动加载流程
在没有安装任何包的时候
vendor\composer\autoload_static.php里面的ComposerStaticInitd599f67bc4dd02223ec31783a7f7938f类只有
public static $classMap和public static function getInitializer(ClassLoader $loader)两个属性或者方法
执行 composer require phpoffice/phpspreadsheet
ComposerStaticInitd599f67bc4dd02223ec31783a7f7938f 会增加
public static $files
public static $prefixLengthsPsr4(这里保存的是包的跟目录(个人理解))
public static $prefixDirsPsr4(根据包的根目录去拿到执行php文件的根目录)
public static $prefixesPsr0
和修改了public static function getInitializer方法(有些语法还不太理解暂时没看,主要是讲一些数据赋值给ClassLoader $loader)
使用composer加载的包
新建一个php文件引入autoload.php
require_once DIR . ‘/vendor/autoload.php’;
调用这个类的功能
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
composer自动加载的执行流程
加载 /composer/autoload_real.php 文件
调用 ComposerStaticInitd599f67bc4dd02223ec31783a7f7938f::getLoader();
getLoader方法执行流程
这里只是单纯的对使用composer包的加载php文件进行理解,跳过其他加载过程
验证PHP版本(platform_check.php)
self::$loader = $loader = new \Composer\Autoload\ClassLoader(实现了PSR-0,PSR-4和classmap类加载器)
加载 vendor\composer\autoload_static.php文件(会验证PHP版本和zend_loader_file_encoded方法,zend_loader_file_encoded存在应该是使用其他逻辑)
调用\Composer\Autoload\ComposerStaticInitd599f67bc4dd05423ece1783a7f7938f::getInitializer($loader)方法
getInitializer方法主要是赋值ComposerStaticInitd599f67bc4dd02223ec31783a7f7938f类中的$prefixLengthsPsr4、$prefixDirsPsr4等给ClassLoader对象
注册自动加载器($loader->register(true);)
当创建phpoffice/phpspreadsheet包里面的对象的时候,找不到这个类会调用注册的自动加载器
loadClass($class) -> findFile($class) -> findFileWithExtension($class, ‘.php’)
loadClass 找到相关文件后,引入(include)这个文件
findFile 查找定义类的文件的路径并返回文件路径
findFileWithExtension 根据$prefixLengthsPsr4、$prefixDirsPsr4来找到这个类 返回文件路径
这就是new \PhpOffice\PhpSpreadsheet\Spreadsheet() 引入Spreadsheet.php文件的大致流程
composer包的关键代码和注释
index.php
require_once __DIR__ . '/vendor/autoload.php'; $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
autoload.php
require_once __DIR__ . '/composer/autoload_real.php';return ComposerStaticInitd599f67bc4dd02223ec31783a7f7938f::getLoader();
composer/autoload_real.php部分代码
<?php // autoload_real.php @generated by Composer class ComposerStaticInitd599f67bc4dd02223ec31783a7f7938f{ private static $loader; public static function getLoader(){ if (null !== self::$loader) { return self::$loader; } // 对PHP版本的验证(version ">= 7.3.0") // __DIR__ 指向当前执行脚本的目录 require __DIR__ . '/platform_check.php'; // 类的自动加载 spl_autoload_register(array('ComposerAutoloaderInitd599f67bc4dd05423ece1783a7f7938f', 'loadClassLoader'), true, true); // __FILE__ D:\....test\vendor\composer\autoload_real.php // \dirname(\dirname(__FILE__)) D:\phpstudy_pro\WWW\test\vendor self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); // 注销自动加载函数 spl_autoload_unregister(array('ComposerAutoloaderInitd599f67bc4dd05423ece1783a7f7938f', 'loadClassLoader')); // function_exists 判断函数是否被定义 $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require __DIR__ . '/autoload_static.php'; // call_user_func把第一个参数作为回调函数调用 // 给$loader赋值一些prefixLengthsPsr call_user_func( \Composer\Autoload\ComposerStaticInitd599f67bc4dd05423ece1783a7f7938f::getInitializer($loader) ); } else { // 个人觉得这里应该是主要判断zend_loader_file_encoded有被定义的模型 } // 注册自动加载器。 $loader->register(true); // 略 return $loader; }}
new \PhpOffice\PhpSpreadsheet\Spreadsheet() 引入Spreadsheet.php文件的大致流程
ClassLoader.php
<?php namespace Composer\Autoload; class ClassLoader{ private $vendorDir; // PSR-4 private $prefixLengthsPsr4 = array(); private $prefixDirsPsr4 = array(); // 省略掉不相关的一些方法 // 类的自动加载入口 public function loadClass($class){ if ($file = $this->findFile($class)) { // 最后加载Spreadsheet.php文件 includeFile($file); return true; }} // 查找定义类的文件的路径。 public function findFile($class){ // 省略不相关的if判断 // composer 包走以下流程 $file = $this->findFileWithExtension($class, '.php'); // 省略不相关的if判断 // 返回文件路径 return $file; } private function findFileWithExtension($class, $ext){ // new \PhpOffice\PhpSpreadsheet\Spreadsheet(); // $class 等于 PhpOffice\PhpSpreadsheet\Spreadsheet // $ext = '.php' // PSR-4 lookup // strtr字符串替换 // 用DIRECTORY_SEPARATOR 来代替 \ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; $first = $class[0]; // 根据首字母去查找包的根目录 // 如果是查找composer包的引用文件,感觉这里的$this->prefixLengthsPsr4感觉作用不大 // $this->prefixLengthsPsr4应该是其他地方有用到吧 if (isset($this->prefixLengthsPsr4[$first])) { $subPath = $class; // strrpos 查找字符串最后一次出现的位置 while (false !== $lastPos = strrpos($subPath, '\\')) { // 拿到包的根目录 $search = "PhpOffice\PhpSpreadsheet\" $subPath = substr($subPath, 0, $lastPos); $search = $subPath . '\\'; if (isset($this->prefixDirsPsr4[$search])) { // $pathEnd = '\Spreadsheet.php' $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); foreach ($this->prefixDirsPsr4[$search] as $dir) { // 判断文件(D:\...\test\vendor\composer/../phpoffice/phpspreadsheet/src/PhpSpreadsheet\Spreadsheet.php)是否存在 if (file_exists($file = $dir . $pathEnd)) { // 存在返回文件 return $file; } } } } } // 略 return false; }} function includeFile($file){ include $file; }
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: