1. 程式人生 > >tp5底層原始碼分析之------tp5.1類的自動載入機制

tp5底層原始碼分析之------tp5.1類的自動載入機制

tp框架作為國內主流框架,目前已經發布了6.0版本,相當於3.*版本是進行了重構,今天我們從原始碼的角度來研究下tp5.1自動載入的實現

    作為單入口框架,從入口檔案看起,入口檔案在public/下,那麼為什麼大多數框架要把入口檔案放到子資料夾下面呢?

 第一,為了動靜分離,因為現在的tp框架一般都是單入口,既然是單入口,那麼必然要做rewrite,如果把靜態檔案和程式檔案放到一起。

框架路由勢必要對每一個請求進行篩選,所以這些框架不約而同的把資原始檔和程式檔案區分開來,放在了不同的資料夾下面,所以從整體

來看,也就是為什麼入口會在子目錄了。

   第二,為了安全,linux下的許可權劃分非常嚴格,分貝氛圍讀,寫,執行。在這個基礎上又分為檔案所有組,所在組,其他組。這樣劃分可以

更好的對檔案許可權進行梳理,避免上傳漏洞(使用者上傳php檔案被執行)等等。

    1.我們來看下入口檔案:

 

    2. tp5.1入口檔案引入載入了base.php檔案,然後base.php檔案中載入了loader.php類,並且執行了Loader::register()靜態方法,我們來看看register方法內部執行了什麼?

 2.1)在第79行也就是register()方法中執行了內建函式apl_autoloader_register(),此函式的第一個引數接收一個匿名函式,或者回調方法,作用是每當php

呼叫了不存在的類時就會執行此函式當中的回撥函式,且攜帶一個引數,值是引入的未存在的帶名稱空間的類名(如果有類名空間),如在base.php20行註冊異常機制,那麼這是攜帶的引數值是:think\Error.

   

 2.2)繼續往下看,Loader類中的80跟81行,分別是獲得本專案的絕對路徑以及獲得vender目錄下composer資料夾的絕對路徑,我們列印輸出看下

2.3)85行後面,判斷是否存在composer資料夾,是否存在autoload_static.php 檔案,因為5.1版本後,php官網不再提供下載版本,只支援通過composer下載,所以這個檔案一定是存在的。然後載入了這個類檔案。

2.4)89行執行了 get_declared_classes() 函式,此函式功能是獲取由當前指令碼中已定義類的名字組成的陣列(包括自己引入的類,和php內建的一些類)。然後90行取出此陣列中最後一個元素,也就是剛剛引入的autoload_static.php中的類,返回值是:Composer\Autoload\ComposerStaticInit3ec0ccb9b30037c3270e4e4566239878

2.5)91行,迴圈將剛才獲得到的類中 成員屬性 複製到本類Loader中, 在商法的類中存在兩個靜態成員屬性:$prefixLengthsPsr4、$prefixDirsPsr4。形式如下圖:

 這兩個成員屬性是根據psr-4規範規則 而生成,不懂的可自己百度瞭解。這裡將成員屬性複製到本類後,後面載入檔案時查詢類的檔案路徑會用到,下面再講。

3)我們來看下注冊名稱空間定義:註冊think和tratis兩個兩個資料夾路徑,呼叫self::addNamespace方法,主要做的事情就是將這兩個名稱空間、檔案路徑以psr-4規範形式 加入到上面所提的兩個成員屬性中$prefixLengthsPsr4、$prefixDirsPsr4。$prefixLengthsPsr4規則:將名稱空間首字母當做第一維陣列的鍵,將名稱空間當做第二維陣列的鍵,將此名稱空間字串長度當做第二維陣列的值。$prefixDirsPsr4規則:將名稱空間當做第一維陣列的鍵,將對應的檔案絕對路徑當做第二維陣列的值,第二位陣列的鍵是自增的索引值。此時本類中的靜態成員屬性$prefixLengthsPsr4、$prefixDirsPsr4的值如下圖:

 4).106行載入類庫對映檔案,

它會查詢專案根目錄下\runtime\classmap.php檔案,將此檔案中的一維陣列值賦值到本類成員屬性$classMap。這個檔案是通過執行tp5.1命令列命令:php think optimize:autoload 生成的。生成的檔案中包含了所有將要引入的類的 類名與檔案絕對路徑 的對映,此檔案會提高尋找類檔案的效率,一般專案完成時生成,如果後續有新建的類的話,此檔案需要重新生成才能尋找到新的類檔案。後面會講到為何會提高載入類的效率。預設是沒有此檔案的。

5)此方法的最後一行118行,自動載入extend目錄,呼叫self::addAutoLoadDir()方法,做的事情是:將專案根目錄下的extend目錄絕對路徑放到 成員屬性 $fallbackDirsPsr4中。

6)Loader::autoload自動載入時執行的方法

  上面說到 spl_autoload_register()函式,如果呼叫不存在的類時將執行此函式中的第一個引數方法。那麼將呼叫本類中的autoload方法。此方法程式碼:

上面說了,此方法的引數$class的值的帶有名稱空間的類名,127行判斷本類中的成員屬性$classAlias中是否存在此類名,如果存在,則將此類名設定別名,開始此屬性值是空陣列。繼續往下,呼叫了self::findFile方法並將類名當做引數傳入,返回$file值,下方140行引入此檔案。我們來看看findFile方法做了哪些事情:

 6.1)143行,首先判斷成員屬性$classmap中是否存在此類名的鍵,如果存在則直接返回。我們上方說到此成員屬性值是執行tp5.1命令列命令生成的,所以生成檔案後就不再往下執行 迴圈判斷檔案是否存在,直接返回檔案路徑,所以可以提高檔案查詢效率。

6.2)

if中執行的邏輯是根據psr-4規範查詢類檔案,具體是這樣:取出這個帶有名稱空間類的第一個字母,判斷成員屬性$prefixLengthsPsr4是否存在此首字母的鍵值,然後迴圈這個鍵值,判斷名稱空間有沒有是否存在$prefixLengthsPsr4二維的鍵,如果存在,根據$prefixDirsPsr4屬性取出名稱空間對應的絕對路徑,然後拼接檔名,判斷檔案是否存在,如果存在則返回檔案的絕對路徑。

6.3)

 迴圈$fallbackDirsPsr4屬性下所有值拼接檔名,返回絕對路徑並判斷檔案是否存在,若存在則返回。

6.4):

 

 根據psr-0規則判斷檔案是否存在並返回,跟上方的psr-4異曲同工

 <