首頁  >  文章  >  php框架  >  ThinkPHP自動載入Loader源碼解析

ThinkPHP自動載入Loader源碼解析

咔咔
咔咔原創
2020-09-16 10:22:172417瀏覽

想了很久終於要開始系列文章的編寫了,期望是寫出提升和麵試都可以搞定的系列文章。 當你看到本文時,如果你發現咔咔沒有編寫到的面試熱點問題或技術難點,期待評論區指出,一起完善。

前言

目前在整理PHP進階路線圖,如有好的建議咔咔會第一時間進行收錄。

一、自動載入loader原始碼分析

1-1 學習目標

  • 類別的自動載入
  • #類別自動載入的兩個種方式
  • #spl_autoload_register必須會使用
  • 實作自訂檔案的類別的自動載入

# 1-2 Composer載入

ThinkPHP自動載入Loader源碼解析
#在這裡插入圖片描述

從上圖咔咔給的解析圖,在base.php中先載入了loader類,接著呼叫了register這個方法。

ThinkPHP自動載入Loader源碼解析來到thinkphp\library\think\Loader.php有一個register的方法,在這個方法裡邊,我們先學習第一個知識點spl_autoload_register()聊聊spl_autoload_register前世今生和簡單使用,直接點擊即可查看。

緊接著就是專案的根路徑和composer的路徑。

ThinkPHP自動載入Loader源碼解析
在這裡插入圖片描述

#從這裡開始就是在載入composer文件,過程也是很簡單

  • 1.判斷composer是否為目錄
  • 2.判斷路徑下面的autoload_static.php是否為檔案
  • # 3.引入autoload_static.php檔案
  • 4.傳回所有已經宣告的所有類別 陣列傳回
  • ##5.取得最後一個類別ComposerStaticInit30742487e00917c888d89ba216f165
  • ##6.判斷ComposerStaticInit30742487e00917c888d89ba216f165b9中是否存在數組中的資料

ThinkPHP自動載入Loader源碼解析#接著可以去vendor\composer\phpload_statstatic.看到這兩個屬性

ThinkPHP自動載入Loader源碼解析這裡有一段程式碼估計有一部分同學會在這裡繞一下self::${$attr} = $composerClass::${$attr};,這裡的 $attr就是'prefixLengthsPsr4', 'prefixDirsPsr4', 'fallbackDirsPsr4', 'prefixesPsr0', 'fallbackDirsPsr0', 'classMap', 'files'這些數據,外層在加一個 $符號。

因此在ComposerStaticInit30742487e00917c888d89ba216f165b9這個類別中直接取得對應的屬性值,也就是上圖的兩個屬性值。

ThinkPHP自動載入Loader源碼解析
在這裡插入圖片描述

#1-3 註冊命名空間

檔案還是thinkphp\library\think\Loader.phpregister方法

在這裡註冊了兩個命令空間,分別為think和traits。接著會進入addNamespace這個方法ThinkPHP自動載入Loader源碼解析addNamespace方法中,加入了Psr4空間

#

ThinkPHP自動載入Loader源碼解析接著來到addPsr4這個方法,會把這兩個命名空間都註冊到ComposerStaticInit1e269472f484e157e90227b420ffca7a類的$prefixLengthsPsr4和$prefixDirs#P#4這兩個屬性中的$#1# #為了驗證上面做一個斷點調試,看到這些資料就應該清晰了,至於traits

也是一樣的註冊方式。

ThinkPHP自動載入Loader源碼解析截止到這裡命名空間就註冊完成了,接下來研究一下psr4命名空間是個什麼東東。

ThinkPHP自動載入Loader源碼解析

1-4 Psr4是什麼玩意

psr是簡單的理解就是檔案路徑、自動載入對應類別的相關規格、目前TP5.1使用的是psr4規格此處的類別是指class、介面、超類別結構

一個完整的類別需要一下結構

\(\)*\

以下規格來自PHP文檔<ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; font-size: 15px; color: #595959; list-style-type: circle;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: rgb(43, 43, 43); margin-top: 10px; margin-bottom: 10px; word-spacing: 2px;">完整的類別名稱必須要有一個頂層命名空間,被稱為"vendor namespace";</p></section></li> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: rgb(43, 43, 43); margin-top: 10px; margin-bottom: 10px; word-spacing: 2px;">完整的類別名稱可以有一個或多個子命名空間;</p></section></li> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: rgb(43, 43, 43); margin-top: 10px; margin-bottom: 10px; word-spacing: 2px;"> 完整的類別名稱必須有一個最終的類別名稱;</p></section></li> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: rgb(43, 43, 43); margin-top: 10px; margin-bottom: 10px; word-spacing: 2px;">#完整的類別名稱中任一部分的下滑線都是沒有特殊意義的;</p></section></li> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: rgb(43, 43, 43); margin-top: 10px; margin-bottom: 10px; word-spacing: 2px;">完整的類名可以由任意大小寫字母組成;</p></section></li> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; font-size: 14px;"><p style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; color: rgb(43, 43, 43); margin-top: 10px; margin-bottom: 10px; word-spacing: 2px;">所有類別名稱都必須是大小寫敏感的。 </p></section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; margin-top: 10px; margin-bottom: 10px; font-size: 14px; word-spacing: 2px;">以下是官方給的一個例子,這個psr規範能理解就盡量去理解它<img src="https://img-blog.csdnimg.cn/20200914110757812.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZhbmdrYW5nNw==,size_16,color_FFFFFF,t_70#pic_center" alt="ThinkPHP自動載入Loader源碼解析" style="max-width:90%"></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; color: black; font-size: 22px; border-bottom: 4px solid rgb(64, 184, 250);"> <span class="prefix" style="display: flex; width: 20px; height: 20px; background-size: 20px 20px; background-image: url(https://my-wechat.mdnice.com/fullstack-1.png); margin-bottom: -22px;"></span><span class="content" style="display: flex; color: #40B8FA; font-size: 20px; margin-left: 25px;">1-5 載入類別庫映射檔</span><span class="suffix" style="display: flex; box-sizing: border-box; width: 200px; height: 10px; border-top-left-radius: 20px; background: RGBA(64, 184, 250, .5); color: rgb(255, 255, 255); font-size: 16px; letter-spacing: 0.544px; justify-content: flex-end; float: right; margin-top: -10px; box-sizing: border-box !important; overflow-wrap: break-word !important;"></span> </h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; line-height: 26px; margin-top: 10px; margin-bottom: 10px; font-size: 14px; word-spacing: 2px;">#到這裡,一定會有一個疑問,這裡怎麼沒有classmap.php這個文件。 <img src="https://img-blog.csdnimg.cn/20200914112731364.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZhbmdrYW5nNw==,size_16,color_FFFFFF,t_70#pic_center" alt="ThinkPHP自動載入Loader源碼解析" style="max-width:90%">不急不慌,先執行<code style="overflow-wrap: break-word; margin: 0px 2px; font-family: " operator mono consolas monaco menlo monospace word-break: break-all color: rgb background: rgba padding: border-radius: height: line-height:>php think optimize:autoload把檔案弄出來ThinkPHP自動載入Loader源碼解析最後會走到addClassMap這個方法,在這個方法中,只是把classmap.php這個檔案的資料賦值給$classMap 而已,沒有什麼它的用法ThinkPHP自動載入Loader源碼解析

##1-6自動載入extend目錄

extend這個目錄用過TP框架的都多少用過的,在這個目錄裡邊可以存放一下自訂的類別庫檔案。

根據下圖可以看到就是使用addAutoLoadDir這個方法進行載入的

ThinkPHP自動載入Loader源碼解析在方法中也只是把extend的路徑賦值給了$fallbackDirsPsr4 這個屬性。

ThinkPHP自動載入Loader源碼解析截止到這裡Loader::register();這部分就結束了,接著我們深入的看一下內部實作和實踐案例。

在上述閱讀原始碼中有四個屬性,簡單的整理一下

ThinkPHP自動載入Loader源碼解析
在這裡插入圖片描述

#二、簡說類別的載入過程

ThinkPHP自動載入Loader源碼解析
在這裡插入圖片描述

在剛開始解析這裡的原始碼時就有一個函數spl_autoload_register

當需要使用的類別沒有被引入時,這個函數會在PHP報錯前被觸發,未定義的類別名稱會被當作參數傳入這裡會直接去執行think\\Loader::autoload這個方法

ThinkPHP自動載入Loader源碼解析經過斷點第一個未載入的類別就是think\Error

ThinkPHP自動載入Loader源碼解析為什麼是think\Error呢!可以在回到thinkphp/base.php看一下,當自動載入完執行完成後第一個執行的類別就是Error

ThinkPHP自動載入Loader源碼解析可以簡單的做個測試,將這Error改為Kaka,進行列印一下,這時的類別就改變為Kaka。到這裡大家對這個類別的自動載入機制就有一定的了解了。

當使用的類別沒有被引入時會把這個類別當做參數傳到thinkphp/library/think/Loader.phpautoload方法中。

ThinkPHP自動載入Loader源碼解析到這裡在進行看一下autoload這個方法

ThinkPHP自動載入Loader源碼解析先從findFile這個方法走,把未因為的類別傳入這個方法中,在findFile這個方法中會直接從classMap這個屬性直接把think\Error這個類別對映的檔案直接回傳

ThinkPHP自動載入Loader源碼解析將think\Error這個類別的完整路徑回傳給autoloadfile變數後,將win環境的大小寫給判斷了一次。

然後直接使用include引入檔案即可,直到返回。

直到這裡就是一次完整的類別的自動載入解析。

ThinkPHP自動載入Loader源碼解析雖然到這裡結束了,但還是得在提一點就是$classMap這個屬性,這個屬性是基於檔案classmap.php來到,這個檔案的產生也是需要執行指令php think optimize:autoload產生的。

當沒有產生這個檔案時程式是如何執行的呢!

之前的所有流程都是一樣的,只有在findFile這裡不一樣,接下來進行簡單的梳理一下。

這時程式碼肯定不會走classMap

####

ThinkPHP自動載入Loader源碼解析先取得think\Error檔案

ThinkPHP自動載入Loader源碼解析然後經過Composer自動載入中的兩個屬性進行取得命名空間,在把think\Error.php檔案進行拼接

ThinkPHP自動載入Loader源碼解析#最終回傳的結果也是D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\thinkphp\library\think\Error.php這個檔案。

這裡的程式碼需要好好的閱讀一下。

類別的自動載入到這裡就是完全結束了。

三、自訂檔案如何實現類別的自動載入

#先建立一個資料夾kaka

ThinkPHP自動載入Loader源碼解析這時在控制器index中引入檔案Kaka.php

ThinkPHP自動載入Loader源碼解析直接進行訪問,這時這個類別肯定會報錯,那麼我們應該怎麼操作一下,就可以直接訪問呢!

ThinkPHP自動載入Loader源碼解析
在這裡插入圖片描述

這個時候就提現到原始碼的重要性了,還記得在自動載入的register 函數中,載入過extend目錄

ThinkPHP自動載入Loader源碼解析
在這裡插入圖片描述

這時在加一個kaka這個目錄,直接進行訪問一下

ThinkPHP自動載入Loader源碼解析沒毛病,直接就出來了。一切OKThinkPHP自動載入Loader源碼解析在這裡在聊一下關於extent的載入方式

在之前聊註冊自動載入類別庫目錄只是說明了一下只是把路徑存到了$fallbackDirsPsr4屬性,沒有細細說,接下來就是說明這些了。

閱讀原始碼只能是實作那然後查看那個

ThinkPHP自動載入Loader源碼解析
在這裡插入圖片描述

只要是定義的類別都會進去到autoload進行自動載入

#同樣也會進入到findFile這個方法

ThinkPHP自動載入Loader源碼解析在findFile這個方法中可以看到這段程式碼,這個屬性是不是很熟悉,就是自動載入extend目錄時加入 $fallbackDirsPsr4屬性的。

ThinkPHP自動載入Loader源碼解析當在findFile中列印參數class時看一下資料

很清楚地可以看到test\Kaka這個類別

ThinkPHP自動載入Loader源碼解析ThinkPHP自動載入Loader源碼解析此時在列印這個$fallbackDirsPsr4屬性裡邊回傳的file

ThinkPHP自動載入Loader源碼解析然後就是使用__include_file來直接include D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\kaka\test\Kaka.php我們定義的檔案。

以上的這個自訂檔案如何實作類別的自動加載,也就是extend的載入方式

四、總結

關於類別自動載入的所有流程就完成了,如有錯誤之處可以在評論區哦!

堅持學習、堅持寫博、堅持分享是咔咔從業以來一直所秉持的信念。希望在偌大互聯網中咔咔的文章能帶給你一絲絲幫助。我是咔咔,下期見。

#

以上是ThinkPHP自動載入Loader源碼解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn