淺談PSR規範與PHP框架中類的自動加載原理

淺談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';
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章