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