在沒有安裝任何包的時候
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 協議》,轉載必須註明作者和本文連結