什么叫Autoload?
在某個(gè)php執(zhí)行上下文中观蜗,在new某個(gè)類臊恋,或者靜態(tài)調(diào)用時(shí)如果某個(gè)類沒有找到,php默認(rèn)會(huì)首先觸發(fā)__autoload回調(diào)墓捻,由回調(diào)嘗試去加載類代碼文件抖仅。這個(gè)回調(diào)由用戶自己實(shí)現(xiàn),通過用戶規(guī)定的類名到代碼文件的映射規(guī)則得到代碼文件路徑砖第,并使用
require/include
函數(shù)去加載代碼文件撤卢。
比如:
<?php
__autoload($clsname) {
require $clsname.'.php';
}
$a = new A();
但是,
__autoload
有一個(gè)不好的地方是只允許注冊(cè)一個(gè)回調(diào)梧兼。同時(shí)放吩,因?yàn)槲覀冊(cè)谑褂靡恍┑谌筋悗?kù)的時(shí)候,經(jīng)常需要維護(hù)各自的autoload
調(diào)用規(guī)則羽杰。所以渡紫,這里在php5.1.2
之后,我們大多使用spl_autoload_register
來替代__autoload
忽洛。
- spl_autoload_register的用法很簡(jiǎn)單:
spl_autoload_register(function($clsname){
$clspath = explode('\\',$clsname);
if($clspath[0] === 'web') {
$clspath[0] = 'src';
}
require dirname(__DIR__).DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR,$clspath).'.php';
});
它的參數(shù)其實(shí)就是一個(gè)__autoload回調(diào)腻惠,你可以多次調(diào)用spl_autoload_register來往隊(duì)列注冊(cè)多個(gè)回調(diào)。
這樣欲虚,使用autoload函數(shù)的好處是集灌,如果我一個(gè)代碼文件中需要使用100個(gè)類,我不需要一個(gè)個(gè)的將其require進(jìn)來复哆,我只需要將其按照一定的規(guī)范組織代碼文件欣喧。然后注冊(cè)一個(gè)autoload函數(shù),按照我們的規(guī)范來自動(dòng)的根據(jù)類名來找到對(duì)應(yīng)的類文件梯找,并require到當(dāng)前執(zhí)行環(huán)境唆阿。
關(guān)于PHP的Autoload,我們不得不提的是PSR0-PSR4規(guī)范锈锤。這兩個(gè)規(guī)范不是PHP的語(yǔ)言標(biāo)準(zhǔn)的一部分驯鳖,只是PHP使用自動(dòng)加載的代碼組織過程中的一個(gè)標(biāo)準(zhǔn)規(guī)范,當(dāng)然你可以完全不遵循這個(gè)規(guī)范久免,但是建議你最好能夠遵循浅辙。
- 一個(gè)簡(jiǎn)單的AutoLoader實(shí)例
/**
* 自動(dòng)加載器,遵循psr-4規(guī)范
* @author fangl
*
*/
class Autoloader {
static $_namespaces = [
'web' => 'src',
];
/**
* 增加命名空間到路徑的映射(以幫助自動(dòng)加載器能夠找到對(duì)應(yīng)的路徑)
* 注意對(duì)應(yīng)的代碼里面的命名空間要和聲明一致阎姥,否則即使文件正確引入记舆,也會(huì)報(bào)找不到類文件錯(cuò)誤
* @param string $namespace 命名空間(只接受一個(gè)字符串)
* @param string $path 命名空間對(duì)應(yīng)的路徑
*/
static function addNameSpace($namespace,$path) {
self::$_namespaces[trim($namespace,'\\/')] = trim($path,'\\/');
}
/**
* 獲取命名空間的加載路徑,如果命名空間不存在呼巴,返回原值
* @param string $namespace
* @return Ambigous <unknown, multitype:string , string>
*/
static function getPath($namespace) {
return isset(self::$_namespaces[$namespace])?self::$_namespaces[$namespace]:$namespace;
}
/**
* 自動(dòng)加載回調(diào)函數(shù)
* @param string $clsname
*/
static function autoload($clsname) {
$clsname = trim($clsname,'\\/');
$clspath = explode('\\',$clsname);
$clspath[0] = self::getPath($clspath[0]);
require APP_ROOT.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR,$clspath).'.php';
}
}
//注冊(cè)自動(dòng)加載
spl_autoload_register(__NAMESPACE__.'\Autoloader::autoload');