什么叫Autoload?
在某個php執行上下文中,在new某個類,或者靜態調用時如果某個類沒有找到,php默認會首先觸發__autoload回調,由回調嘗試去加載類代碼文件。這個回調由用戶自己實現,通過用戶規定的類名到代碼文件的映射規則得到代碼文件路徑,并使用
require/include
函數去加載代碼文件。
比如:
<?php
__autoload($clsname) {
require $clsname.'.php';
}
$a = new A();
但是,
__autoload
有一個不好的地方是只允許注冊一個回調。同時,因為我們在使用一些第三方類庫的時候,經常需要維護各自的autoload
調用規則。所以,這里在php5.1.2
之后,我們大多使用spl_autoload_register
來替代__autoload
。
- spl_autoload_register的用法很簡單:
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';
});
它的參數其實就是一個__autoload回調,你可以多次調用spl_autoload_register來往隊列注冊多個回調。
這樣,使用autoload函數的好處是,如果我一個代碼文件中需要使用100個類,我不需要一個個的將其require進來,我只需要將其按照一定的規范組織代碼文件。然后注冊一個autoload函數,按照我們的規范來自動的根據類名來找到對應的類文件,并require到當前執行環境。
關于PHP的Autoload,我們不得不提的是PSR0-PSR4規范。這兩個規范不是PHP的語言標準的一部分,只是PHP使用自動加載的代碼組織過程中的一個標準規范,當然你可以完全不遵循這個規范,但是建議你最好能夠遵循。
- 一個簡單的AutoLoader實例
/**
* 自動加載器,遵循psr-4規范
* @author fangl
*
*/
class Autoloader {
static $_namespaces = [
'web' => 'src',
];
/**
* 增加命名空間到路徑的映射(以幫助自動加載器能夠找到對應的路徑)
* 注意對應的代碼里面的命名空間要和聲明一致,否則即使文件正確引入,也會報找不到類文件錯誤
* @param string $namespace 命名空間(只接受一個字符串)
* @param string $path 命名空間對應的路徑
*/
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;
}
/**
* 自動加載回調函數
* @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';
}
}
//注冊自動加載
spl_autoload_register(__NAMESPACE__.'\Autoloader::autoload');