PHP自動(dòng)加載

文章總結(jié)了PHP的自動(dòng)加載機(jī)制,包含魔法函數(shù) __autoload()和spl autoload函數(shù)。

緣起

PHP開(kāi)發(fā)過(guò)程中,需要通過(guò)include、include_once篡石、require或require_once引入定義的類(lèi),如圖:

<?php
require_once('./ClassA.php');
require_once('./ClassB.php');
require_once('./ClassC.php');
...

當(dāng)需要引入的類(lèi)比較少的時(shí)候西采,沒(méi)有什么大問(wèn)題夏志,但是當(dāng)需要引入的類(lèi)非常多時(shí),就會(huì)出現(xiàn)大量的include或require語(yǔ)句苛让,這樣會(huì)導(dǎo)致遺漏或者包含不必要的類(lèi)文件沟蔑。因此,類(lèi)的自動(dòng)加載(autoload)機(jī)制應(yīng)運(yùn)而生狱杰。
autoload機(jī)制主要用來(lái)自動(dòng)加載類(lèi)瘦材,該機(jī)制使PHP程序有可能在使用類(lèi)時(shí)才自動(dòng)引入類(lèi)文件,而不是一開(kāi)始就將所有的類(lèi)文件引入仿畸。

自動(dòng)加載函數(shù)__autoload()

PHP程序中食棕,當(dāng)我們要使用的類(lèi)未導(dǎo)入時(shí),會(huì)自動(dòng)調(diào)用__autoload()函數(shù)错沽,此函數(shù)是我們?cè)诔绦蛑凶远x的簿晓,通過(guò)這個(gè)函數(shù)可以加載需要引入的類(lèi)。
為了更好的說(shuō)明__autoload()函數(shù)千埃,下面舉個(gè)例子進(jìn)行說(shuō)明憔儿,以下是項(xiàng)目的目錄:

+ first
+--   ClassA.php
+ second
+--   ClassB.php
-  autoload.php
-  index.php

首先我們來(lái)看ClassA.php:

<?php
//test/first/ClassA.php
class ClassA
{
    public  function fun()
    {
        echo "ClassA is running...\n";
    }
}

ClassB和ClassA類(lèi)似,只有一個(gè)簡(jiǎn)單的函數(shù)fun():

<?php
//test/second/ClassB.php
class ClassB
{
    public  function fun()
    {
        echo "ClassB is running...\n";
    }
}

require放可、include函數(shù)

如果采用原始的require或者include方法谒臼,需要分別引入ClassA朝刊、ClassB文件,程序正常打印結(jié)果蜈缤。

<?php
//test/index.php
require_once  __DIR__.'./first/ClassA.php';
require_once  __DIR__.'./second/ClassB.php';

$classA = new ClassA();
$classB = new ClassB();
$classA->fun();
$classB->fun();

__autoload()函數(shù)

為了使用__autoload()函數(shù)拾氓,我們需要單獨(dú)新建一個(gè)文件,這里我們新建了一個(gè)autoload.php文件底哥,然后在index.php文件里調(diào)用include或require引入該文件咙鞍,此時(shí)當(dāng)有未引入的類(lèi)時(shí),程序會(huì)自動(dòng)調(diào)用__autoload()函數(shù)趾徽,并將類(lèi)名作為參數(shù)傳入奶陈。
__autoload()函數(shù),首先需要確定類(lèi)名對(duì)應(yīng)的文件名附较,然后通過(guò)調(diào)用is_readable()函數(shù)判斷該文件是否可讀,如果可讀則調(diào)用require_once引入相應(yīng)的類(lèi)文件潦俺。

<?php
//test/autoload.php
function __autoload($className)
{
    if($className == 'ClassA'){
        $classpath = __DIR__.'\\first\\'.$className.'.php';
    }else{
        $classpath = __DIR__.'\\second\\'.$className.'.php';
    }
    if (is_readable($classpath)) {
        require_once($classpath);
    }
}

此時(shí)拒课,需要修改index.php文件,該文件刪掉了ClassA和ClassB的引入事示,同時(shí)引入了autoload.php文件早像。這里只需要一行即可引入所需的類(lèi),當(dāng)所需的類(lèi)達(dá)到數(shù)百個(gè)時(shí)肖爵,__autoload()函數(shù)的優(yōu)勢(shì)就會(huì)彰顯無(wú)疑卢鹦。另外,__autoload()函數(shù)只有在需要相應(yīng)的類(lèi)時(shí)才會(huì)主動(dòng)引入劝堪,假設(shè)這里不需要ClassB類(lèi)冀自,那么程序不會(huì)引入。如果是采用require或include函數(shù)時(shí)秒啦,必須在程序的開(kāi)始交代清楚熬粗,否則會(huì)報(bào)錯(cuò)。

<?php
//test/index.php
require_once  __DIR__.'./autoload.php';

$classA = new ClassA();
$classB = new ClassB();
$classA->fun();
$classB->fun();

但是余境,autoload()函數(shù)存在一個(gè)嚴(yán)重的缺點(diǎn):__autoload() 是全局函數(shù)且只能定義一次驻呐,不夠靈活。另外芳来,所有類(lèi)名和文件名的對(duì)應(yīng)關(guān)系都在__autoload()函數(shù)中實(shí)現(xiàn)含末,這會(huì)導(dǎo)致該函數(shù)非常臃腫。

spl autoload

SPL是Standard PHP Library(標(biāo)準(zhǔn)PHP庫(kù))的縮寫(xiě)即舌。它是PHP引入的一個(gè)擴(kuò)展庫(kù)佣盒,其主要功能包括autoload機(jī)制的實(shí)現(xiàn)及包括各種Iterator接口或類(lèi)。其有以下幾個(gè)函數(shù):

spl_autoload_register:注冊(cè) _autoload() 函數(shù)
spl_autoload_unregister:注銷(xiāo)已注冊(cè)的_autoload()函數(shù)
spl_autoload_functions:返回所有已注冊(cè)的_autoload()函數(shù)
spl_autoload_call:嘗試所有已注冊(cè)的_autoload()函數(shù)來(lái)加載類(lèi)
spl_autoload :_autoload()函數(shù)的默認(rèn)實(shí)現(xiàn)
spl_autoload_extionsions: 注冊(cè)并返回 spl_autoload 函數(shù)使用的默認(rèn)文件擴(kuò)展名顽聂。

spl_autoload_register()函數(shù)實(shí)現(xiàn)了一個(gè)autoload調(diào)用堆棧沼撕,我們可以向這個(gè)堆棧注冊(cè)多個(gè)__autoload()函數(shù)宋雏,當(dāng)PHP找不到類(lèi)名時(shí),就會(huì)調(diào)用autoload堆棧务豺,一個(gè)一個(gè)地去調(diào)用自定義的__autoload()函數(shù)磨总,實(shí)現(xiàn)自動(dòng)加載功能。
舉例說(shuō)明spl_autoload_register()函數(shù)的用法笼沥,以下是項(xiàng)目目錄

+ first
+--   ClassA.php
+ second
+--   ClassB.php
-  autoloadA.php
-  autoloadB.php
-  index.php

項(xiàng)目增加了autoloadA.php蚪燕、autoloadB.php文件,并且修改了index.php文件奔浅。autoloadA.php文件用于加載first文件夾下的類(lèi)馆纳,autoloadB.php用于加載second文件夾下的類(lèi)。通過(guò)調(diào)用spl_autoload_register()函數(shù)可以注冊(cè)多個(gè)__autoload()函數(shù)汹桦。

<?php
//test/autoloadA.php
function __autoloadA($className)
{
    $classpath = __DIR__.'\\first\\'.$className.'.php';
    if (is_readable($classpath)) {
        require_once($classpath);
    }
}
spl_autoload_register('__autoloadA');
<?php
//test/autoloadB.php
function __autoloadB($className)
{
    $classpath = __DIR__.'\\second\\'.$className.'.php';
    if (is_readable($classpath)) {
        require_once($classpath);
    }
}
spl_autoload_register('__autoloadB');

文件index.php修改如下鲁驶,此時(shí)即可以實(shí)現(xiàn)注冊(cè)多個(gè)__autoload()函數(shù)。此時(shí)會(huì)發(fā)現(xiàn)舞骆,與最開(kāi)始使用require或include引入文件一樣需要兩行才能實(shí)現(xiàn)所有類(lèi)的引入钥弯,貌似并沒(méi)有更簡(jiǎn)單。但是假設(shè)first督禽、second文件夾下各有100個(gè)類(lèi)需要引入脆霎,則使用require或include函數(shù)引入需要200行,而使用spl_autoload_register()函數(shù)引入根本不需要改變代碼狈惫。

<?php
//test/index.php
require_once __DIR__ . './autoloadA.php';
require_once __DIR__ . './autoloadB.php';

$classA = new ClassA();
$classB = new ClassB();
$classA->fun();
$classB->fun();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末睛蛛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子胧谈,更是在濱河造成了極大的恐慌忆肾,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件菱肖,死亡現(xiàn)場(chǎng)離奇詭異难菌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蔑滓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)郊酒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人键袱,你說(shuō)我怎么就攤上這事燎窘。” “怎么了蹄咖?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵褐健,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蚜迅,這世上最難降的妖魔是什么舵匾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮谁不,結(jié)果婚禮上坐梯,老公的妹妹穿的比我還像新娘。我一直安慰自己刹帕,他們只是感情好吵血,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著偷溺,像睡著了一般蹋辅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挫掏,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天侦另,我揣著相機(jī)與錄音,去河邊找鬼尉共。 笑死褒傅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的爸邢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼拿愧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼杠河!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起浇辜,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤券敌,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后柳洋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體待诅,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年熊镣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卑雁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绪囱,死狀恐怖测蹲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鬼吵,我是刑警寧澤扣甲,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站齿椅,受9級(jí)特大地震影響琉挖,放射性物質(zhì)發(fā)生泄漏启泣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一示辈、第九天 我趴在偏房一處隱蔽的房頂上張望寥茫。 院中可真熱鬧,春花似錦顽耳、人聲如沸坠敷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)膝迎。三九已至,卻和暖如春胰耗,著一層夾襖步出監(jiān)牢的瞬間限次,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工柴灯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卖漫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓赠群,卻偏偏與公主長(zhǎng)得像羊始,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子查描,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 說(shuō)說(shuō)PHP的autoLoad(http://www.cnblogs.com/yjf512/archive/2012...
    古則閱讀 455評(píng)論 0 1
  • 在PHP開(kāi)發(fā)過(guò)程中突委,如果希望從外部引入一個(gè)class,通常會(huì)使用include和require方法冬三,去把定義這...
    四月不見(jiàn)閱讀 1,051評(píng)論 0 0
  • 參考PHP中的自動(dòng)加載 什么叫Autoload匀油? 在某個(gè)php執(zhí)行上下文中,在new某個(gè)類(lèi)勾笆,或者靜態(tài)調(diào)用時(shí)如果某個(gè)...
    云龍789閱讀 548評(píng)論 0 3
  • 折騰大半天這個(gè)自動(dòng)加載文件敌蚜,才搞清楚,特別感謝peter 需求: 系統(tǒng)開(kāi)發(fā)過(guò)程中,隨著類(lèi)文件不斷增加,在文件中引用...
    古佛青燈度流年閱讀 1,051評(píng)論 2 2
  • 星期五的晚上取劫,媽媽說(shuō)辛苦學(xué)習(xí)一個(gè)星期,帶我們?nèi)バ麓髽峭嬉煌嫠汀N覀兊搅肆鶚牵页粤宋覑?ài)吃的牛板面哥哥吃了薯格啃勉。我們?cè)?..
    唐康凱閱讀 156評(píng)論 0 0