分析ThinkPHP5的源码(1) : 类的自动加载
前文
Composer 下載ThinkPHP5.1的源碼,每個框架它都必須都有一個“類的自動加載”機制 ,我們都知道PHP引入文件是需要require 、 include 才能使用別的類文件中的方法。
比如我需要寫一個公共文件 model.php
include "model.php" include "model2.php"class User {//code.. }但是!如何當公共類庫文件很多的時候,每次都需要手動引入,就顯得非常麻煩,不利于/不方便維護管理。
所以PHP引入了一個spl_autoload_register() 的類自動加載,TP框架就是借助了 spl_autoload_register() 來完成類的自動加載。
TP5框架入口加載機制
學習框架源碼的第一步,先找到入口文件 public/index.php ,然后一步步跟進流程,看下代碼執行的過程。
- 第一行:定義命名空間就不贅述了。。
- 第二行:去加載基礎文件 base.php ,是位于上一層目錄的 think目錄下
打開Base.php ,第16行就會去加載 Loader.php 文件 (就是TP5自動加載的類庫) ,Loader.php 是TP5封裝的底層基礎類庫。
再引用了核心文件 Loader.php
調用類庫的 Loader::register() 的方法
發現都用了spl_autoload_register()的系統函數,其他框架也是同理。
都是會在框架的第一步“入門文件”就進行類的自動加載機制,針對底層進行封裝。
TP5中的Loader::register() 其實做了2件事:
- 內部自定義一個autoload() 去進行框架的底層深度封裝
- 為了支持 Composer 自動加載 安裝第三方的類庫插件(Vendor),都是遵循PSR-4的風格統一,那么加載composer類的 autoload_static.php 后,再去加載對應的插件類庫。
分析Loader::register的執行流程
如下截圖:
分析TP5執行 Loader::register() 的注冊自動加載方法 ,( 是調用不存在的類的時候才會執行spl_autoload_register())
運用3元運算符,如果有參數就執行其他自定義類,沒就 加載本類的autoload() 方法
調用 self::gerRootPath() 獲取項目的根目錄
這里就是走 Composer的加載機制,然后組織一個Vendor的決定路徑 ,self::$composerPath
判斷是否有Vendor的目錄,再判斷是否有auto_static的文件 ,有就加載composer目錄下的auto_static.php
分析Composer自動加載——類文件
在邏輯往下走,判斷是否有Vendor的目錄,再判斷是否有auto_static的文件 ,有就加載composer目錄下的auto_static.php
auto_static.php
發現定義了2個屬性分別是: $prefixLengthsPsr4 、$prefixDirsPsr4 ,這是什么意思呢?
定義數組,有個key和value,比如 $prefixLengthsPsr4 (PSR4的長度)
- t key代表一個命名空間 ,代表think\composer\ 命名空間 ,首字母代表類,把某些類放進去來,15 代表字符的長度。
- a key也是代表一個命名空間,代表:app ,用首字母代表,把某些類放進去, 4是這個字符的長度。
2個斜線是轉義字符,比如 think\\composer\\ 等同于 think\composer\
$prefixDirsPsr4 把每個命名空間的類對應的目錄列出來
- 比如think\composer 這個命名空間 在src下
- app\\ 這個命名空間就在根目錄的application
比如通過 Compsoe r安裝 swoole、workermam、phpexcel 就把相應的規則追加數組上 填進來。
總結: composer的統一加載機制的地方,每次composer新類庫的時候,都會往這個屬性追加 命名空間 以及類庫的目錄路徑 。
分析Composer自動加載——屬性賦值
回到Loader::register()方法。
// Composer自動加載支持if (is_dir(self::$composerPath)) {if (is_file(self::$composerPath . 'autoload_static.php')) {require self::$composerPath . 'autoload_static.php';$declaredClass = get_declared_classes();$composerClass = array_pop($declaredClass);foreach (['prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'] as $attr) {if (property_exists($composerClass, $attr)) {self::${$attr} = $composerClass::${$attr};}}} else {self::registerComposerLoader(self::$composerPath);}}// 注冊命名空間定義self::addNamespace(['think' => __DIR__,'traits' => dirname(__DIR__) . DIRECTORY_SEPARATOR . 'traits',]);再返回 Loader::register() 方法接著放下分析:
如果存在Vendor目錄,再判斷是否有 composer_static.php ,有就執行如下:
執行了 get_declared_classes 這個系統函數,返回由當前腳本中已定義類的名字組成的數組。
我們打印這個get_declared_classes
得到目前所有加載的類,最后require加載的是 composer類。
所以,我們上面的 array_pop 彈出最后一個元素,賦值后的 $composerClass ,就是composer的類。
這個命令空間那么長的其實就是 composer目錄下的autoload_static.php
再繼續往下執行
property_exists : 檢查對象或類是否具有該屬性
我們知道autoload_static.php 存在有
- prefixLengthsPsr4
- $prefixDirsPsr4
- $classMap
等一眾的方法,composer的 stacis.php這些屬性以及值 ,再賦值作為Loader類的某個屬性再處理。
上面的寫法等同 :
self::prefixLengthsPsr4 self::prefixDirsPsr4打印這些屬性返回:
為什么這樣去做?后續要集合多個屬性再Map,加載文件的時候用這些屬性。
總結: 把composere下的auto_static的PSR4的屬性以及值賦值到Loader的PSR4屬性中
分析Composer自動加載——注冊命名空間
3. 再接下來,無論是不是數組,都再把命名空間拼接組裝好,再調用self::addPsr4()
4. 查看 addPsr4() 方法
注冊的時候走的是“296” 行 。
因為之前 self::$prefixDirsPsr4 里的屬性只是composer的autp_static.php 上的,只有 think\ 跟 app\ ,并沒有think 跟traits 這2個屬性。
public static $prefixDirsPsr4 = array ('think\\composer\\' => array (0 => __DIR__ . '/..' . '/topthink/think-installer/src',),'app\\' => array (0 => __DIR__ . '/../..' . '/application',),);
6. 這樣就完成 think、traits下的命名空間注冊到Loader類的PSR4屬性中。
加載類庫映射文件
再往下執行:
總結: 把tp5的核心的 think 和 traits 命名空間注冊到PSR4里,方便后續調用,實在屬性多個數組統一自動加載。
自動加載extend目錄
再往下執行
進去 self::addAutoLoadDir() 方法:
把當前extend的目錄也加載到 Loader類 $fallbackDirsPsr4 的屬性中。
總結
- prefixDirsPsr4 (對應類的目錄)
- prefixLengthsPsr4 (對應類的命名長度)
- fallbackDirsPsr4 (對應extend的目錄)
我們拿到很多變量成員、命令空間、目錄路徑等都賦值到 Loader類的多個PSR4的屬性中。
后續再拿這些屬性做自動加載配置。
總結
以上是生活随笔為你收集整理的分析ThinkPHP5的源码(1) : 类的自动加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常用的《短信中心号码》收集
- 下一篇: java button click事件_