PHP的類自動加載機制

在PHP開發過程當中,若是但願從外部引入一個class,一般會使用include和require方法,去把定義這個class的文件包含進來。 這個在小規模開發的時候,沒什麼大問題。但在大型的開發項目中,這麼作會產生大量的require或者include方法調用,這樣不因下降效率,並且使 得代碼難以維護,何況require_once的代價很大。php

在PHP5以前,各個PHP框架若是要實現類的自動加載,通常都是按照某種約定本身實現一個遍歷目錄,自動加載全部符合約定規則的文件的類或函數。 固然,PHP5以前對面向對象的支持並非太好,類的使用也沒有如今頻繁。 在PHP5後,當加載PHP類時,若是類所在文件沒有被包含進來,或者類名出錯,Zend引擎會自動調用__autoload 函數。此函數須要用戶本身實現__autoload函數。 在PHP5.1.2版本後,可使用spl_autoload_register函數自定義自動加載處理函數。當沒有調用此函數,默認狀況下會使用SPL 自定義的spl_autoload函數。數組

一、 __autoload示例:安全

1
2
3
4
5
function  __autoload( $class_name ) {
    echo  '__autload class:' , $class_name , '<br />' ;
}
  
new  Demo();


以上的代碼在最後會輸出:__autload class:Demo。
並在此以後報錯顯示: Fatal error: Class ‘Demo’ not found框架

咱們通常使用_autoload自動加載類以下:函數

<?php 
  
   function  __autoload( $class_name ) { 
       require_once  ( $class_name  . 「 class .php」); 
  } 
    $memo = new  Demo(); 

  
咱們能夠看出_autoload至少要作三件事情,第一件事是根據類名肯定類文件名,第二件事是肯定類文件所在的磁盤路徑(在咱們的例子是最簡單的狀況, 類與調用它們的PHP程序文件在同一個文件夾下),第三件事是將類從磁盤文件中加載到系統中。第三步最簡單,只須要使用include/require即 可。要實現第一步,第二步的功能,必須在開發時約定類名與磁盤文件的映射方法,只有這樣咱們才能根據類名找到它對應的磁盤文件。ui

所以,當有大量的類文件要包含的時候,咱們只要肯定相應的規則,而後在__autoload()函數中,將類名與實際的磁盤文件對應起來,就能夠實 現lazy loading的效果。從這裏咱們也能夠看出__autoload()函數的實現中最重要的是類名與實際的磁盤文件映射規則的實現。spa

但如今問題來了,假如在一個系統的實現中,假如須要使用不少其它的類庫,這些類庫多是由不一樣的開發工程師開發,其類名與實際的磁盤文件的映射規則 不盡相同。這時假如要實現類庫文件的自動加載,就必須在__autoload()函數中將全部的映射規則所有實現,所以__autoload()函數有可 能會很是複雜,甚至沒法實現。最後可能會致使__autoload()函數十分臃腫,這時即使可以實現,也會給未來的維護和系統效率帶來很大的負面影響。 在這種狀況下,在PHP5引入SPL標準庫,一種新的解決方案,即spl_autoload_register()函數。code

二、spl_autoload_register()函數對象

此函數的功能就是把函數註冊至SPL的__autoload函數棧中,並移除系統默認的__autoload()函數。下面的例子能夠看出:blog

 

<span style= "line-height: 26px;" > 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(); //結果:</span><span style="font-family: Simsun;font-size:16px; ">SPL load class:Test</span>

 


語法: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()函數的初始化調用方法:

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)組合在一塊兒使用以嘗試去加載一個類,而且在全部的自動加載器都不能找到那個類的情 況下失敗。

if (spl_autoload_call( 'className' ) && class_exists ( 'className' ,false)){    
    } else  {    
  

 

  SPL自動加載功能是由spl_autoload() ,spl_autoload_register(), spl_autoload_functions() ,spl_autoload_extensions()和spl_autoload_call()函數提供的。

相關文章
相關標籤/搜索