#1. 爲何須要類自動加載機制php
##緣由: 在PHP開發過程當中,若是但願從外部引入一個class,一般會使用include和require方法,去把定義這個class的文件包含進來。這個在小規模開發的時候,沒什麼大問題。但在大型的開發項目中,這麼作會產生大量的require或者include方法調用,這樣不因下降效率,並且使得代碼難以維護,何況require_once的代價很大。數組
##解決 在PHP5以前,各個PHP框架若是要實現類的自動加載,通常都是按照某種約定本身實現一個遍歷目錄,自動加載全部符合約定規則的文件的類或函數。 固然,PHP5以前對面向對象的支持並非太好,類的使用也沒有如今頻繁。安全
在PHP5後,當加載PHP類時,若是類所在文件沒有被包含進來,或者類名出錯,Zend引擎會自動調用__autoload 函數。此函數須要用戶本身實現__autoload函數。框架
在PHP5.1.2版本後,可使用spl_autoload_register函數自定義自動加載處理函數。當沒有調用此函數,默認狀況下會使用SPL自定義的spl_autoload函數。函數
教程ui
#2. __autoload(類名)函數.net
一、 __autoload示例: function __autoload($class_name) { echo '__autload class:', $class_name, '<br />'; } new Demo();
以上的代碼在最後會輸出:__autload class:Demo
。code
並在此以後報錯顯示: Fatal error: Class ‘Demo’ not found
對象
咱們通常使用_autoload自動加載類以下:blog
function __autoload($class_name) { require_once ($class_name . 「class.php」); } $memo= new Demo();
##1._autoload三件事 咱們能夠看出_autoload至少要作三件事情, 第一件事是根據類名肯定類文件名,第二件事是肯定類文件所在的磁盤路徑(在咱們的例子是最簡單的狀況,類與調用它們的PHP程序文件在同一個文件夾下),第三件事是將類從磁盤文件中加載到系統中。第三步最簡單,只須要使用include/require便可。要實現第一步,第二步的功能,必須在開發時約定類名與磁盤文件的映射方法,只有這樣咱們才能根據類名找到它對應的磁盤文件。
所以,當有大量的類文件要包含的時候,咱們只要肯定相應的規則,而後在__autoload()函數中,將類名與實際的磁盤文件對應起來,就能夠實現lazy loading的效果。
從這裏咱們也能夠看出__autoload()函數的實現中最重要的是類名與實際的磁盤文件映射規則的實現。
##2._autoload的問題
但如今問題來了,假如在一個系統的實現中,假如須要使用不少其它的類庫,這些類庫多是由不一樣的開發工程師開發,其類名與實際的磁盤文件的映射規則
不盡相同。這時假如要實現類庫文件的自動加載,就必須在__autoload()函數中將全部的映射規則所有實現,所以__autoload()函數有可能會很是複雜,甚至沒法實現。
最後可能會致使__autoload()函數十分臃腫,這時即使可以實現,也會給未來的維護和系統效率帶來很大的負面影響。在這種狀況下,在PHP5引入SPL標準庫,一種新的解決方案,即spl_autoload_register()函數。
##3._autoload廢棄的緣由
咱們一個php項目依賴於多個框架,若是每個框都都有一個_autoload方法,那他就會報函數重複定義的錯誤,
#3. spl_autoload_register()函數。 ##php版本>5.3 spl_autoload_register()函數取代._autoload函數
此函數的功能就是把函數註冊至SPL的__autoload函數棧中,並移除系統默認的__autoload()函數。下面的例子能夠看出:
function __autoload($class_name) { echo '__autload class:', $class_name, '<br />'; } function classLoader($class_name) { echo 'SPL load class:', $class_name, '<br />'; } spl_autoload_register('classLoader'); new Test();//結果:SPL load class:Test
語法:bool spl_autoload_register ( [callback $autoload_function] ) 接受兩個參數:一個是添加到自動加載棧的函數,另一個是加載器不能找到這個類時是否拋出異常的標誌。第一個參數是可選的,而且默認指向spl_autoload()函數,這個函數會自動在路徑中查找具備小寫類名和.php擴展或者.ini擴展名,或者任何註冊到spl_autoload_extensions()函數中的其它擴展名的文件。
##註冊類方法
<?php class CalssLoader { public static function loader($classname) { $class_file = strtolower($classname).".php"; if (file_exists($class_file)){ require_once($class_file); } } } // 方法爲靜態方法 spl_autoload_register('CalssLoader::loader'); $test = new Test();
一旦調用spl_autoload_register()函數,當調用未定義類時,系統會按順序調用註冊到spl_autoload_register()函數的全部函數,而不是自動調用__autoload()函數。若是要避免這種狀況,需採用一種更加安全的spl_autoload_register()函數的初始化調用方法:
[php] view plain copy print? if(false === spl_autoload_functions()){ if(function_exists('__autoload')){ spl_autoload_registe('__autoload',false); } }
spl_autoload_functions()函數會返回已註冊函數的一個數組,若是SPL自動加載棧尚未被初始化,它會返回布爾值false。而後,檢查是否有一個名爲__autoload()的函數存在,若是存在,能夠將它註冊爲自動加載棧中的第一個函數,從而保留它的功能。以後,能夠繼續註冊自動加載函數。
還能夠調用spl_autoload_register()函數以註冊一個回調函數,而不是爲函數提供一個字符串名稱。如提供一個如array('class','method')這樣的數組,使得可使用某個對象的方法。
下一步,經過調用spl_autoload_call('className')函數,能夠手動調用加載器,而不用嘗試去使用那個類。這個函數能夠和函數class_exists('className',false)組合在一塊兒使用以嘗試去加載一個類,而且在全部的自動加載器都不能找到那個類的狀況下失敗。
f(spl_autoload_call('className') && class_exists('className',false)){ } else { }
#4. SPL自動加載功能
SPL自動加載功能是由 spl_autoload() , spl_autoload_register(), spl_autoload_functions() ,spl_autoload_extensions()和spl_autoload_call()函數提供的。
#5. 注意點: 註冊的是函數名不要小括號
<?php function __autoload($class_name) { echo '__autload class:', $class_name, '<br />'; } spl_autoload_register('autoload1'); spl_autoload_register('autoload2'); function autoload1($class){ require __DIR__.''.$class.'.php'; } function autoload2($class){ require __DIR__.''.$class.'.php'; } ?>