在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()函數提供的。