PHP中類自動載入的方式

來源:互聯網
上載者:User
這篇文章主要介紹了關於PHP中類自動載入的方式,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

  最近在學習composer,發現從接觸PHP到現在已經遇到了三種關於PHP中類的自動載入方式,這其中包括PHP內建的類的自動載入方式、PHP的第三方的依賴管理工具composer的載入方式以及PHP的Yaf架構下的自動載入方式。本篇部落客要是針對PHP5內建的載入方式進行詳細介紹,composer和Yaf下類的自動載入將在接下來的時間裡分兩篇和大家一起學習。

1.手動載入方式

  像C和C++等語言,在PHP中需要使用另一個檔案中的相關的類、方法時,可以使用include、include_once、require或者require_once將所用的檔案包含進工程裡面。其中,四者的區別如下。

  • include將套用一個檔案,如果檔案不存在,則給出一個提示,跳過繼續執行;

  • include_once也是套用一個檔案,但是只會套用一次,如果檔案不存在,則繼續執行;

  • require表示套用一個檔案,如果檔案不存在,則中斷程式的執行;

  • require_once也是套用一個檔案,且只會套用一次,如果檔案不存在,則中斷程式的執行;

  以上四種方式是需要什麼檔案的時候,手動在程式當中包含進檔案。這在項目的規模比較小的時候,是可以的;但是隨著項目規模的擴大,要通過手動的方式載入每個檔案所需要的類簡直是一場噩夢。

  為了省事,在載入的時候可以通過set_include_path()設定載入的路徑,同樣也可以通過get_include_path()擷取載入的路徑。關於set_include_path()和get_include_path(),我也是剛剛接觸,這裡只對set_include_path()作簡要的介紹,以後遇到問題再加以補充。

  首先,set_include_path()是在指令碼中動態對php.ini中的include_path進行動態修改,而這個include_path就是對include和require(下文中如果不進行特別的說明,include代表include和include_once,require代表著require和require_once)的路徑進行設定,或者說是預定義。假如,我們在一個main.php檔案中需要使用projname/home/lib/mylib/test檔案夾下的a.php、b.php、c.php......,如果沒有設定包含的路徑的話,那麼寫成如下的形式:

< ? php        include("projname/home/lib/mylib/test/a.php");        include("projname/home/lib/mylib/test/b.php");        include("projname/home/lib/mylib/test/c.php");  ......

  這樣,每個include都需要包含絕對路徑,顯得很麻煩。如果在需要被包含的檔案之前加上set_include_path(“projname/home/lib/mylib/test”),那麼就可以寫成如下所示的形式:

< ? php    set_include_path("projname/home/lib/mylib/test");    include("a.php");    include("b.php");    include("c.php");    ......

  相比於第一種費時費力的寫法,第二種明顯省去了很多的時間,但是仍然是要將每個檔案包含進來,只是簡化了包含的路徑而已。當然,上面所說的情況是所需要的檔案都存在於一個檔案夾中,如果檔案存在於不同的檔案夾中,那麼可以添加多條的set_include_path()語句,此時如果include或者require中的檔案包含的檔案名稱在多個目錄下出現,那麼只會包含最先出現在set_include_path目錄中的檔案;如果所有的set_include_path指定的檔案夾中都沒有對應的檔案,而檔案名稱恰好出現在當前的檔案夾中,則直接包含目前的目錄下的對應的檔案。

  get_include_path()函數只適用於擷取當前的包含路徑。

  2._autoload和spl_autoload_register()自動載入方式

  為了將雙手從類的載入方式中解放出來,在PHP5及以後的版本中提供了一個自動載入的機制---autoload。Autoload可以使類在確實被需要的情況下才會被載入進來,也就是所謂的lazy loading,而不是一開始就include或者require所有的類檔案。其中PHP提供的自動載入機制又分為兩種---__autoload()以及spl_autoload_register()。

  1). __autoload機制

  在PHP5中運行程式的過程中,如果發現某一個類並沒有被包含進來,那麼就會運行__autoload自動載入機制,將所需要的類載入進來。其寫法如下:

< ? phppublic function  __autoload($classname) {$fileName = $classname."php";if (file_exist($fileName)) {require_once("$fileName");} else {echo $fileName." doesn't exist!"}}

  根據這個程式寫法,我們可以得到如下的結論:保證自動載入機制的的原則就是要使得類名和檔案名稱具有一種對應關係,類名+尾碼構成了這個類所在的檔案的名字。如果這個檔案確實存在,那麼就根據$fileName將該類載入進來。如果檔案不存在,則提示使用者,檔案不存在。總的來說自動載入機制包括三個步驟:

  • 根據類名確定檔案名稱,也就是確定一種類名和檔案名稱之間的統一對應規則;

  • 根據檔案名稱在磁碟上找到相應的對應檔案(例子中是最簡單的情況,就是類與調用他們的PHP檔案都在同一個目錄下);如果不在同一個目錄下,那麼可以使用set_include_path()指定要載入的路徑;

  • 將磁碟檔案載入到檔案系統中,這一步只是用一般的include和require包含相應的類檔案;

  __autoload()實作類別的自動載入的原則就是:類名和檔案名稱之間具有一種統一的對應關係,這是在一個系統中實現__autoload的關鍵所在。但是一個系統可能是有不同的人員所開發,如果在開發之前沒有約定統一的標準,則可能存在不同的對應規則,導致需要在__autoload()中實現多種載入規則,那麼可能導致__autoload()函數非常的臃腫。為瞭解決這個這個問題,PHP還提供了一個自動載入機制---spl_autoload_register().

  2). spl_autoload_register()機制

  SPL是Standard PHP Library(標準PHP庫)的縮寫,是PHP5引入的一個擴充庫。SPL autoload是通過將函數指標autoload_func指向自動裝載函數實現的。SPL具有兩個不同的自動裝載函數,分別是spl_autoload和spl_autoload_call,通過將autoload_fun指向這兩個不同的載入函數地址可以實現不同的自動載入機制。

  • spl_autoload

  spl_autoload是SPL實現的預設的自動載入函數,是一個可以接受兩個參數的函數。其中第一個函數為$class_name,表示要載入的類名;第二個參數是$file_extension為選擇性參數,表示類檔案的副檔名。$file_extension中可以指定多個副檔名,副檔名之間用分號隔開即可,不指定副檔名,則使用預設的副檔名.inc或者.php。spl_autoload首先將$class_name變為小寫,然後在所有的include_path中搜尋$ class_name.inc或者$class_name.php檔案。如果找到對應的檔案,就載入對應的類。其實可以手動的使用spl_autoload("xxxx",".php")來實現xxxx類的載入。這其實和require/include差不多,但是,spl_autoload相對來說靈活一點,因為可以指定多個副檔名。

  前面說到,spl_autoload_register中包含的函數指標autoload_func用於指定要使用的載入函數。那麼,我們必須將對應的函數地址賦值給autoload_func,spl_autoload_register()正實現了給函數指標autoload_func賦值的功能。如果spl_autoload_register()函數中不含有任何的參數,則預設是將spl_autoload()賦值給autoload_func.

  • spl_autoload_call 

  SPL模組的內部其實還存在著一個autoload_functions,其本質上是一個雜湊表,或者為了直觀的理解,我們將其想像成一個容器,裡面的各個元素都是指向載入函數的指標。spl_autoload_call的實現機制其實也比較簡單,按照一定的順序遍曆這個容器,執行裡面的函數指標指向的載入函數,每執行一個指標之後都會檢查所需要的類是否已經完成載入。如果完成了載入,則退出。否則繼續接著向下執行。如果執行完所有的載入函數之後,所需要的類仍然沒有完成載入,則spl_autoload_call()直接退出。這也就是說即使使用了autoload機制,也不一定能夠完成類的載入,其關鍵在於看你如何建立你的自動載入函數。

  既然,存在一個autoload_functions,那麼如何將建立的自動載入函數添加到其中呢?spl_autoload一樣,同樣使用spl_autoload_register()將載入函數註冊到autoload_functions中。當然可以通過spl_autoload_unregister()函數將已經註冊的函數從autoload_functions從雜湊表中刪除。

  這裡需要說明的一點是spl_autoload_register實現自動載入的順序。spl_autoload的自動載入順序為:首先判斷autoload_func是否為空白,如果autoload_func為空白,則查看是否定義了__autoload函數,如果沒有定義,則返回,並報錯;如果定義了__autoload()函數,則返回載入的結果。如果autoload_func不為空白,直接執行autoload_func指標指向的函數,不會檢查__autoload是否定義。也就是說優先使用spl_autoload_register()註冊過的函數。

  根據以上介紹,如果autoload_func為非空是就不能自動執行__autoload()函數了。如果想在使用spl_autoload_register()函數的情況下,依然可以使用__autoload()函數,則可以將__autoload函數通過spl_autoload_register()添加到雜湊表中,即,spl_autoload_register(__autoload())。下面的程式碼範例分別說明了如何註冊普通的方法和類的靜態公有方法。

  普通函數的註冊方法。

<? php/*** @ 普通函數的調用方法,可以調用尾碼名分別為.php和.class.php的類檔案*/function loadFielEndOfPhp($classname) {$fileName = $classname.".php";if (file_exist($fileName)) {require_once("$fileName");} else {echo $fileName." doesn't exist!"}}function loadFielEndOfClassPhp($classname) {$fileName = $classname.".class.php";if (file_exist($fileName)) {require_once("$fileName");} else {echo $fileName." doesn't exist!"}spl_autoload_register("loadFielEndOfPhp"); spl_autoload_register("loadFielEndOfClassPhp");}

  類中靜態載入函數的註冊方法。

<? php/*** @ 類中靜態成員函數的調用方法,可調用尾碼名為.php和.class.php的檔案*/    class test {public static function loadFielEndOfPhp($classname) {$fileName = $classname.".php";if (file_exist($fileName)) {require_once("$fileName");}else {echo $fileName." doesn't exist!"}}public static function loadFielEndOfClassPhp($classname) {$fileName = $classname.".class.php";if (file_exist($fileName)) {require_once("$fileName");}else {echo $fileName." doesn't exist!"}}spl_autoload_register(array("test","loadFielEndOfPhp")); //spl_autoload_register("test::loadFielEndOfPhp");         //上一行的另一種寫法,不是使用數組的形式完成註冊;spl_autoload_register(array("test","loadFielEndOfClassPhp"));//spl_autoload_register("test::loadFielEndOfClassPhp");    //第三行的另一種寫法,不是使用數組的形式完成註冊;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.