1. __autoload
這是一個(gè)自動(dòng)加載函數(shù),在PHP5中,當(dāng)我們實(shí)例化一個(gè)未定義的類(lèi)時(shí),就會(huì)觸發(fā)此函數(shù)。看下面例子:
./myClass.php
<?php
class myClass {
public function __construct() {
echo "myClass init'ed successfuly!!!";
}
}
?>
./index.php
<?php
// we've writen this code where we need
function __autoload($classname) {
$filename = "./". $classname .".php";
include_once($filename);
}
// we've called a class ***
$obj = new myClass();
?>
從上面能看到這是兩個(gè)文件,下面的index.php 中,new了個(gè) myClass類(lèi),但是明顯本文件不存在,現(xiàn)在就會(huì)自動(dòng)調(diào)用 __autoload函數(shù),并 把 “myClass”這個(gè)類(lèi)名字符串 直接作為參數(shù)傳給__autoload, 此時(shí)自動(dòng)加載函數(shù)內(nèi)部就可以引入該文件了,引入后就正常初始化該類(lèi)了。 該函數(shù)在PHP 7.2.0后被廢棄了。
2. spl_autoload_register
spl_autoload_register 可以將 函數(shù)自動(dòng)注冊(cè),也就是說(shuō),當(dāng)PHP文件內(nèi)訪問(wèn)了一個(gè)不存在的類(lèi)時(shí),會(huì)自動(dòng)去調(diào)用該函數(shù),然后執(zhí)行該函數(shù)內(nèi)部的函數(shù),看起來(lái)和 autoload的作用是一樣的。但是其實(shí)spl_autoload_register 這個(gè)函數(shù)功能更強(qiáng)大, autoload的參數(shù) 僅僅是一個(gè)函數(shù)名,這是定死的。并且只能聲明一次, 使用了autoload后,就不能再次使用該函數(shù)了。
請(qǐng)注意:一個(gè)項(xiàng)目中只能有一個(gè)__autoload, 如果在PHP在執(zhí)行過(guò)程中遇到兩個(gè)__autoload會(huì)直接報(bào)錯(cuò)的。
很明顯,autoload無(wú)法滿足要求, 所以就有了SPL擴(kuò)展,spl_autoload_register接受函數(shù)名或閉包,或數(shù)組作為參數(shù),在閉包內(nèi)部,即可引入對(duì)應(yīng)的文件了。并且spl_autoload_register可以注冊(cè)一個(gè) 自動(dòng)加載隊(duì)列,先注冊(cè)的,先調(diào)用。
參數(shù)
autoload_function
欲注冊(cè)的自動(dòng)裝載函數(shù)。如果沒(méi)有提供任何參數(shù),則自動(dòng)注冊(cè) autoload 的默認(rèn)實(shí)現(xiàn)函數(shù)spl_autoload()。
throw
此參數(shù)設(shè)置了 autoload_function 無(wú)法成功注冊(cè)時(shí), spl_autoload_register()是否拋出異常。
prepend
如果是 true,spl_autoload_register() 會(huì)添加函數(shù)到隊(duì)列之首,而不是隊(duì)列尾部。
可以結(jié)合require_once一起使用。如:
function_1(){
$clsName = str_replace("\\",DIRECTORY_SEPARATOR, $class_name);
if (is_file(__DIR__.DIRECTORY_SEPARATOR."src".DIRECTORY_SEPARATOR.$clsName . '.php')) {
//文件內(nèi)部有類(lèi)名 為 TestClass_1的類(lèi)
require_once(__DIR__.DIRECTORY_SEPARATOR."src".DIRECTORY_SEPARATOR.$clsName.'.php');
}
}
function_2(){
$clsName = str_replace("\\",DIRECTORY_SEPARATOR, $class_name);
if (is_file(__DIR__.DIRECTORY_SEPARATOR."Module".DIRECTORY_SEPARATOR.$clsName . '.php')) {
//文件內(nèi)部有類(lèi)名為T(mén)estClass_2的類(lèi)
require_once(__DIR__.DIRECTORY_SEPARATOR."Module".DIRECTORY_SEPARATOR.$clsName.'.php');
}
}
spl_autoload_register('function_1');
spl_autoload_register('function_2');
$obj = new TestClass_2(); //當(dāng)前沒(méi)有TestClass_2這個(gè)類(lèi),于是自動(dòng)調(diào)用function_1, 引入了文件,但是引入的文件中仍然沒(méi)有TestClass_2這個(gè)類(lèi),于是又自動(dòng)調(diào)用function_2, 引入了文件,此時(shí)正常初始化
3.相關(guān)的其他SPL函數(shù)

3.1 spl_autoload_call
該函數(shù)是需要用戶顯示調(diào)用所有已注冊(cè)的 autoload函數(shù)的。 作用在 spl_autoload_register之后。 傳入函數(shù)名字即可。即可手動(dòng)引入文件了。
3.2 spl_autoload_functions
可以獲取到所有已經(jīng)注冊(cè)的autoload函數(shù), 也是作用在 spl_autoload_register之后的。
3.3 spl_autoload_extensions
注冊(cè)并返回spl_autoload函數(shù)使用的默認(rèn)文件擴(kuò)展名, 但是此接口和spl_autoload函數(shù),用處不大。spl_autoload 是autoload的默認(rèn)實(shí)現(xiàn),意思就是spl_autoload對(duì)autoload進(jìn)行了又一次封裝,在默認(rèn)情況下,本函數(shù)先將類(lèi)名轉(zhuǎn)換成小寫(xiě),再在小寫(xiě)的類(lèi)名后加上 .inc 或 .php 的擴(kuò)展名作為文件名,然后在所有的包含路徑(include paths)中檢查是否存在該文件。
__autoload 函數(shù)是用來(lái)處理自動(dòng)加載的函數(shù),在 PHP 找不到指定類(lèi)時(shí)就會(huì)去調(diào)用自動(dòng)加載類(lèi),加載所需要的類(lèi)。
__autoload 只是一個(gè)抽象定義,實(shí)現(xiàn)(實(shí)現(xiàn)就是定義如何加載,加載的規(guī)則是什么,加載的文件是什么等等)是交給用戶的,而 spl_autoload 則是 SPL 所定義的 autoload 一種實(shí)現(xiàn)。spl_autoload 函數(shù)所實(shí)現(xiàn)的加載規(guī)則就是去 include paths 中查找對(duì)于的類(lèi)。spl_autoload 遵循是是 psr-0 的載入規(guī)則,而 include paths 就是載入時(shí)被查詢的路徑。
其他自己實(shí)現(xiàn)的 autoload 類(lèi)都可以通過(guò) spl_autoload_register 進(jìn)行注冊(cè),注冊(cè)之后就可以在需要類(lèi)時(shí)自動(dòng)調(diào)用被注冊(cè)的方法進(jìn)行加載了。 spl_autoload 也是 autoload 的一種實(shí)現(xiàn),按理也是需要注冊(cè)的,只不過(guò)因?yàn)槭莾?nèi)部的默認(rèn)實(shí)現(xiàn),所有已經(jīng)自動(dòng)注冊(cè)在 PHP 里了。
spl_autoload 如今來(lái)看并沒(méi)有太多用處,應(yīng)該是因?yàn)闅v史問(wèn)題殘留在 PHP 中的,目前絕大多數(shù)程序都沒(méi)有使用 spl_autoload 去做自動(dòng)加載,因?yàn)樗囊?guī)則已經(jīng)定死,并不適合衍生一些功能。
因?yàn)?PHP 只有一個(gè)自動(dòng)加載方法,所以 SPL 的 spl_autoload 和 spl_autoload_register 要爭(zhēng)搶這個(gè)方法,所以在 SPL 的 C 實(shí)現(xiàn)中,用了好多折衷的辦法。在沒(méi)有使用 spl_autoload_register 注冊(cè)任何自定的自動(dòng)加載函數(shù)時(shí), PHP 的自動(dòng)加載方法是掛在 spl_autoload 下的,而 spl_autoload_register 注冊(cè)了自動(dòng)加載函數(shù)后,PHP 的自動(dòng)加載方法是掛在 spl_autoload_call 這個(gè)方法下的,而 spl_autoload 也會(huì)成為一個(gè)備選項(xiàng)進(jìn)入 spl_autoload_register 的自動(dòng)加載隊(duì)列。