PHP框架中的檔案載入的實現(自動載入/PSR規範/名稱空間)

codefly發表於2019-02-25

今天有同學問了PHP框架中的各個目錄下面的各個.php檔案是如何實現載入的,他上網搜尋,一搜一大把,都是再說php中有自動載入函式,是自動載入函式完成類檔案的自動載入的,但是具體的還是不明白。是的,框架的自動載入的完成的確是依靠PHP提供的自動載入的函式來完成,但是除此以外,還有幾個需要注意點,如果不搞明白,就不能真正的理解框架具體的實現方式。那麼這裡就總結一下:

(1):總所周知,php完成自動載入是依靠__autoload()函式或者spl_autoload_register()函式來實現,具體的使用方法大家都知道,這裡就不贅述了。這裡說一下兩者之間的區別。

目前,實現自動載入,大家幾乎都使用spl_autoload_register()函式,而不是使用__autoload()函式,這是因為,在同一個指令碼中__autoload()函式不能夠重複進行定義,而spl_autoload_register()函式卻可以實現註冊多次載入函式,這樣我們就可以更加靈活的進行檔案的自動載入了。

下面的程式碼因為重複定義了__autoload()函式,所以會報錯。

<?php
//定義載入函式1
function __autoload($class_name){
       //載入檔案
       require_once("./".$class_name.".php");
}
//定義載入函式2
function __autoload($class_name){
       //載入檔案
       require_once("./".$class_name.".php");
}
?>複製程式碼

但是下面使用spl_autoload_register()函式就不會報錯:

<?php
function autoload_one($class_name){
      require_once("");
}
function autoload_two($class_name){
      require_once("");
}
spl_autoload_register(`autoload_one`);
spl_autoload_register(`autoload_two`);
?>複製程式碼

(2):參考上面的兩個函式的程式碼,傳遞的引數都是$class_name,也就是需要載入的類的名稱。如果我們例項化一個類,就會自動的將該類的名稱賦值給$class_name。如果我們例項化一個帶有名稱空間的類,就會將該類所處的名稱空間以及該類的名稱傳遞給$class_name。看下面的程式碼:

<?php
function __autoload($class_name){
      require_once("./".$class_name.".php");
      echo $class_name."<br/>";  //列印出UserParent
}
$a = new UserParent(); //例項化User名稱空間下的Parent類
?>複製程式碼

好了,現在我們就可以得到想要例項化的類的名稱,那麼下面的問題就是如何根據傳遞過來的類的名字來找到該類檔案,並進行載入了。

(3):在瞭解如何根據傳遞過來的類的名稱(包括名稱空間)去找類之前,我們還必須要了解一下PHP程式設計的規範,瞭解了規範,你就會徹底明白到底是怎麼回事。這裡說的PHP開發規範指的是PSR規範,它是PHP開發的事實標準,主流的PHP開發框架都是遵循PSR開發規範。比如ThinkPHP框架就支援PSR開發標準。

PHP框架中的檔案載入的實現(自動載入/PSR規範/名稱空間)

PSR規範目前包含五個具體的規範(包括PSR-0,PSR-1,PSR-2,PSR-3,PSR-4)。這裡我們具體的說一下PSR-0以及PSR-4規範,其他的規範我們這裡就不提,有興趣的同學可以自己百度。PSR-0規範如下:

1):名稱空間必須與絕對路徑一致。
2):類名的首字母必須要大寫。
3):除了入口檔案以外,其他的.php檔案中必須只有一個類,不能有可執行的程式碼。

根據PSR-o規範,名稱空間空間必須要與絕對路徑一致,也就是說如果你要將一個名為HomeController的類檔案設定在AppUserController的名稱空間之下,那麼就必須要將該檔案放到當前目錄下面(入口檔案)下面的./App/User/Controller資料夾下面。反過來一樣,如果你需要在./App/User/Controller資料夾下面建立一個類檔案,那麼這個類檔案的名稱空間也必須是AppUserController。

PSR-4規範基本和PSR-0規範一致,區別在與PSR-4是對下劃線(underscore)的定義不同。PSR-4中,在類名中使用下劃線沒有任何特殊含義。而PSR-0則規定類名中的下劃線_會被轉化成目錄分隔符。

瞭解了上面的三點,我們就可以理清主流PHP框架中實現類檔案載入的機制了。

(1):在入口檔案中定義類檔案的載入處理函式,比如說spl_autoload_register()函式。

(2):index.php處理使用者的請求,處理傳遞過來的引數,解析路由,分析出需要請求的類名,方法名。

(3):例項化類,根據傳入的類名稱,根據PSR-0/PSR-4規範,分析出類檔案的路徑,進行載入

大體的步驟就是這樣的,當然了,一個成熟的框架真正的載入流程要比上面說的複雜的多得多,有興趣的可以研究框架原始碼。


補:另外,因為主流的框架都廣泛的採用名稱空間,所以就會大量的使用use來引用其他各個名稱空間下定義的各個類。有些同學可能沒有看到require()來載入類檔案,所以就以為use可以自動的完成檔案的載入。其實並不是這樣的,use並不會進行類檔案的載入。之所以use之後就完成了載入,還是因為框架定義了自動載入函式的原因,使用use來引入類與使用new來例項化類的時候,都會觸發類的自動載入。

相關文章