?
想了很久終于要開始系列文章的編寫了,期望是寫出提升和面試都可以搞定的系列文章。 當(dāng)你看到本文時(shí),如果你發(fā)現(xiàn)咔咔沒有編寫到的面試熱點(diǎn)問題或者技術(shù)難點(diǎn),期待評(píng)論區(qū)指出,一起完善。
?
前言
目前在整理PHP進(jìn)階路線圖,如有好的建議咔咔會(huì)第一時(shí)間進(jìn)行收錄。
一、自動(dòng)加載loader源碼分析
1-1 學(xué)習(xí)目標(biāo)
-
類的自動(dòng)加載 -
類自動(dòng)加載的倆種方式 -
spl_autoload_register必須會(huì)使用 -
實(shí)現(xiàn)自定義文件的類的自動(dòng)加載
1-2 Composer加載

從上圖咔咔給的解析圖,在base.php中首先加載了loader類,接著調(diào)用了register這個(gè)方法。
來到
thinkphplibrarythinkLoader.php
有一個(gè)register的方法,在這個(gè)方法里邊,我們先學(xué)習(xí)第一個(gè)知識(shí)點(diǎn)spl_autoload_register()
聊聊spl_autoload_register前世今生和簡(jiǎn)單使用,直接點(diǎn)擊即可查看。
緊接著就是項(xiàng)目的根路徑和composer的路徑。

從這里開始就是在加載composer文件,過程也是很簡(jiǎn)單
-
1.判斷composer是否為目錄 -
2.判斷路徑下面的autoload_static.php是否為文件 -
3.引入autoload_static.php文件 -
4.返回所有已經(jīng)聲明的所有類 數(shù)組返回 -
5.獲取最后一個(gè)類ComposerStaticInit30742487e00917c888d89ba216f165b9 -
6.判斷ComposerStaticInit30742487e00917c888d89ba216f165b9中是否存在數(shù)組中的數(shù)據(jù)
接著可以去vendorcomposerautoload_static.php文件中可以看到這倆個(gè)屬性
這里有一段代碼估計(jì)有一部分同學(xué)會(huì)在這里繞一下
self::${$attr} = $composerClass::${$attr};
,這里的$attr
就是'prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'
這些數(shù)據(jù),外層在加一個(gè)$
符號(hào)。
從而在ComposerStaticInit30742487e00917c888d89ba216f165b9
這個(gè)類中直接獲取對(duì)應(yīng)的屬性值,也就是上圖的倆個(gè)屬性值。

1-3 注冊(cè)命名空間
文件還是thinkphplibrarythinkLoader.php
的register
方法
在這里注冊(cè)了倆個(gè)命令空間,分別為think和traits。然后會(huì)進(jìn)入到addNamespace這個(gè)方法中在
addNamespace
方法中,添加了Psr4空間
接著來到addPsr4這個(gè)方法,會(huì)把這倆個(gè)命名空間都注冊(cè)到
ComposerStaticInit1e269472f484e157e90227b420ffca7a類的$prefixLengthsPsr4和$prefixDirsPsr4這倆個(gè)屬性中
為了驗(yàn)證上面做一個(gè)斷點(diǎn)調(diào)試,看到這些數(shù)據(jù)就應(yīng)該清晰了,至于
traits
也是一樣的注冊(cè)方式。
截止到這里命名空間就注冊(cè)完成了,接下來研究一下psr4命名空間是個(gè)什么東東。
1-4 Psr4是什么玩意
psr是簡(jiǎn)單的理解就是文件路徑、自動(dòng)加載對(duì)應(yīng)類的相關(guān)規(guī)范、目前TP5.1使用的是psr4規(guī)范
此處的類是指class、接口、超類結(jié)構(gòu)
一個(gè)完整的類需要一下結(jié)構(gòu)<命名空間>(<子命名空間>)*<類名>
以下規(guī)范來源于PHP文檔
-
完整的類名必須要有一個(gè)頂級(jí)命名空間,被稱為 "vendor namespace";
-
完整的類名可以有一個(gè)或多個(gè)子命名空間;
-
完整的類名必須有一個(gè)最終的類名;
-
完整的類名中任意一部分中的下滑線都是沒有特殊含義的;
-
完整的類名可以由任意大小寫字母組成;
-
所有類名都必須是大小寫敏感的。
以下是官方給的一個(gè)例子,這個(gè)psr規(guī)范能理解就盡量去理解它
1-5 加載類庫映射文件
到這里,肯定會(huì)有一個(gè)疑問,這里怎么沒有classmap.php這個(gè)文件。不急不慌,先執(zhí)行
php think optimize:autoload
把文件弄出來最終會(huì)走到
addClassMap
這個(gè)方法,在這個(gè)方法中,只是把classmap.php
這個(gè)文件的數(shù)據(jù)賦值給$classMap
而已,沒有什么其它的用法
1-6 自動(dòng)加載extend目錄
extend這個(gè)目錄用過TP框架的都多少用過的,在這個(gè)目錄里邊可以存放一下自定義的類庫文件。
根據(jù)下圖可以看到就是使用addAutoLoadDir
這個(gè)方法進(jìn)行加載的
在方法中也僅僅是把extend的路徑賦值給了
$fallbackDirsPsr4
這個(gè)屬性。
截止到這里
Loader::register();
這部分就結(jié)束了,接著我們深入的看一下內(nèi)部實(shí)現(xiàn)和實(shí)踐案例。
在以上閱讀源碼中有四個(gè)屬性,簡(jiǎn)單的整理一下

二、簡(jiǎn)說類的加載過程

在剛剛開始解析這里的源碼時(shí)就有一個(gè)函數(shù)spl_autoload_register
當(dāng)需要使用的類沒有被引入時(shí),這個(gè)函數(shù)會(huì)在PHP報(bào)錯(cuò)前被觸發(fā),未定義的類名會(huì)被當(dāng)作參數(shù)傳入這里會(huì)直接去執(zhí)行think\Loader::autoload
這個(gè)方法
經(jīng)過斷點(diǎn)第一個(gè)未加載的類就是thinkError
為什么是thinkError呢!可以在回到
thinkphp/base.php
看一下,當(dāng)自動(dòng)加載完執(zhí)行完成后第一個(gè)執(zhí)行的類就是Error
可以簡(jiǎn)單的做個(gè)測(cè)試,將這Error改為Kaka,進(jìn)行打印一下,這時(shí)的類就改變?yōu)镵aka。到這里大家對(duì)這個(gè)類的自動(dòng)加載機(jī)制就有一定的了解了。
當(dāng)使用的類沒有被引入時(shí)會(huì)把這個(gè)類當(dāng)做參數(shù)傳到thinkphp/library/think/Loader.php
的autoload
方法中。
到這里在進(jìn)行看一下autoload這個(gè)方法
先從findFile這個(gè)方法走,把未因?yàn)榈念悅魅脒@個(gè)方法中,在findFile這個(gè)方法中會(huì)直接從classMap這個(gè)屬性中直接把thinkError這個(gè)類映射的文件直接返回出來
將thinkError這個(gè)類的完整路徑返回給
autoload
的file
變量后,把win環(huán)境的大小寫給判斷了一次。
然后直接使用include
引入文件即可,直到返回。
直到這里就是一次完整的類的自動(dòng)加載解析。
雖然到這里結(jié)束了,但是還是得在提一點(diǎn)就是
$classMap
這個(gè)屬性,這個(gè)屬性是基于文件classmap.php
來到,這個(gè)文件的生成也是需要執(zhí)行命令php think optimize:autoload
生成的。
當(dāng)沒有生成這個(gè)文件時(shí)程序是如何執(zhí)行的呢!
之前的所有流程都是一樣的,只有在findFile
這里不一樣,接下來進(jìn)行簡(jiǎn)單的梳理一下。
這時(shí)代碼肯定不會(huì)走classMap
先獲取thinkError文件
然后經(jīng)過Composer自動(dòng)加載中的倆個(gè)屬性進(jìn)行獲取命名空間,在把thinkError.php文件進(jìn)行拼接
最終返回的結(jié)果也是
D:phpstudy_proWWWThinkPHPSourceCodeAnalysisthinkphplibrarythinkError.php
這個(gè)文件。
這里的代碼需要好好的閱讀一下。
類的自動(dòng)加載到這里就是完全結(jié)束了。
三、自定義文件如何實(shí)現(xiàn)類的自動(dòng)加載
先創(chuàng)建一個(gè)文件夾kaka
這時(shí)在控制器index中引入文件Kaka.php
直接進(jìn)行訪問,這時(shí)這個(gè)類肯定會(huì)報(bào)錯(cuò),那么我們應(yīng)該怎么操作一下,就可以直接訪問呢!

這個(gè)時(shí)候就提現(xiàn)到源碼的重要性了,還記得在自動(dòng)加載的register
函數(shù)中,加載過extend目錄

這時(shí)在加一個(gè)kaka這個(gè)目錄,直接進(jìn)行訪問一下
沒毛病,直接就出來了。一切OK
在這里在聊一下關(guān)于extent的加載方式
在之前聊注冊(cè)自動(dòng)加載類庫目錄只是說明了一下只是把路徑存到了$fallbackDirsPsr4
屬性,沒有細(xì)細(xì)說,接下來就是說明這些了。
閱讀源碼只能是實(shí)現(xiàn)那然后查看那

只要是定義的類都會(huì)進(jìn)去到autoload進(jìn)行自動(dòng)加載
同樣也會(huì)進(jìn)入到findFile
這個(gè)方法
在findFile這個(gè)方法中可以看到這段代碼,這個(gè)屬性是不是很熟悉,就是自動(dòng)加載extend目錄時(shí)添加到
$fallbackDirsPsr4
屬性的。
當(dāng)在findFile中打印參數(shù)class時(shí)看一下數(shù)據(jù)
很清楚地可以看到testKaka
這個(gè)類
此時(shí)在打印一下這個(gè)
$fallbackDirsPsr4
屬性里邊返回的file
然后就是使用
__include_file
來直接includeD:phpstudy_proWWWThinkPHPSourceCodeAnalysiskakatestKaka.php
我們定義的文件。
以上的這個(gè)自定義文件如何實(shí)現(xiàn)類的自動(dòng)加載,并且也就是extend
的加載方式
四、總結(jié)
關(guān)于類自動(dòng)加載的所有流程就完成了,如有錯(cuò)誤之處可以在評(píng)論區(qū)哦!
?
堅(jiān)持學(xué)習(xí)、堅(jiān)持寫博、堅(jiān)持分享是咔咔從業(yè)以來一直所秉持的信念。希望在偌大互聯(lián)網(wǎng)中咔咔的文章能帶給你一絲絲幫助。我是咔咔,下期見。
?