淺談PSR規範與PHP框架中類的自動加載原理
在PHP中,如果要實例化的類不在當前文件中,那麼需要require引入類所在的文件。但在項目編程中,頻繁因此引入文件十分影響開發效率,因此誕生了PHP類自動加載方法。
__autoload()函數(不推薦)
__autoload是早期的自動加載方法,用戶可以重新定義這個方法。在文件中調用一個不存在的類會在報錯前自動調用此方法,用戶可以在方法內定義自動加載邏輯。
function __autoload($class){
require_once $class.'.php';
}
//當Class類不存在時自動調用__autoload函數,傳入參數'Class'
$class = new Class();
這種自動加載方式目前已不被推薦,未來可能被棄用。
spl_autoload_register()註冊自動加載器
PHP5以後, spl_autoload_register() 函數可以註冊任意數量的自動加載器,當調用未定義的類時調用自動加載器的方法,代替__autoload的作用。
function autoload($class){
require_once $class.'.php';
}
spl_autoload_register('autoload'); //將autoload函數註冊爲自動加載器
//當Class類不存在時自動調用autoload('Class');
$class = new Class();
PSR規範與框架自動加載原理
目前絕大多數框架都是遵循PSR規範,然後通過註冊自己的自動加載器實現自動加載。
PSR0規範
- 一個完全標準的命名空間(namespace)和類(class)的結構是這樣的:\()*
- 每個命名空間(namespace)都必須有一個頂級的空間名(namespace)(“組織名(Vendor Name)”)。
- 每個命名空間(namespace)中可以根據需要使用任意數量的子命名空間(sub-namespace)。
- 從文件系統中加載源文件時,空間名(namespace)中的分隔符將被轉換爲 DIRECTORY_SEPARATOR。
- 類名(class name)中的每個下劃線都將被轉換爲一個DIRECTORY_SEPARATOR。下劃線在空間名(namespace)中沒有什麼特殊的意義。
- 完全標準的命名空間(namespace)和類(class)從文件系統加載源文件時將會加上.php後綴。
組織名(vendor name),空間名(namespace),類名(class name)都由大小寫字母組合而成。
以上大致可以理解爲: 一個類所在的命名空間與類所在文件相對項目跟目錄路徑相對應。
例如一個項目目錄結構如下:
User類所在文件user.php相對於項目根目錄路徑是 ./app/index/controller/user.php 那麼遵從psr規範,User類所在命名空間應定義爲: namespace app\index\controller
遵從psr規則後,便可以類似下方代碼註冊自動加載器:
function autoLoad($class)
{
$class = strtr($class, '\\', '/');
$file = APP_PATH . '/' . strtolower($class) . '.php';
if (is_file($file)) {
require $file;
} else {
$arr = explode('/', $class);
throw new \Exception\Error('目標文件' . htmlspecialchars(end($arr)) . ' 不存在', 404);
}
}
spl_autoload_register('autoLoad');
自動加載流程如下:
在user.php中自動調用Base類
Base 類命名空間與 User 類相同
namespace app\index\controller
class User extends Base{
...
}
//本命名空間下Base類不存在,自動調用 app\index\controller\Base類,相當於調用函數 autoLoad('app\index\controller\Base');
*在user.php 中調用model\user
namespace app\index\controller
use app\common\model\User
class User extends Base{
$model = new User();
}
//使用use引入類,new User相當於 new app\common\model\User();
//此時傳入autoLoad的參數爲 'app\common\model\User';