PHP 命名空間 namespace / 類別名 use / 框架自動載入 機理的

相比 PHP5.2 版本 PHP5.3 新增了三大主要新特性php

命名空間 linux

延遲靜態綁定 web

lambda匿名函數thinkphp

命名空間的出現也使PHP能夠更加合理的組織項目結構,同時經過命名空間和自動載入機制一大批 PHP 的 MVC 框架也隨之出現,明瞭的項目結構的同時也按需載入,進一步減輕內存壓力,加快執行效率。bootstrap

由於命名空間是對目錄結構友好的yii2

namespace Home\Controller;

class IndexController
{

}

而 PHP5.2 以前是按造類的下劃線去作相似 命名空間 的定義的app

class Home_Controller_IndexController
{

}

 

1、 命名空間 及 USE 的本質

php 的 use 關鍵字並非馬上導入所use的類,它只是聲明某類的完整類名(命名空間::類標示符),然後你在上下文中使用此類時系統纔會根據 use 聲明獲取此類的完整類名 而後利用自動加載機制進行載入框架

 

namespace Home\Controller;

use Home\Model\User;
use Home\Model\Order as OrderList;

class IndexController
{

    public function index()
    {
        //只有當你調用此類時,系統纔會根據 use 聲明獲取此類的完整類名 而後利用自動加載機制進行載入
        $user = new User();
        $order = new OrderList();
    }
}

就像以下的代碼 自動載入函數是在 use 兩個類以後方纔實現的 由於 use 並不會當即使用此類 只有在你調用此類時系統纔會在找不到此類的狀況下經過 autoload 函數動態延遲加載,若仍加載不到,則報錯yii

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require 'vendor/autoload.php';

$app = new \Slim\App();
$app->get('/hello/{name}', function (Request $request, Response $response) {
    $name = $request->getAttribute('name');
    $response->getBody()->write("Hello, $name");
    return $response;
});

$app->run();

2、剖析 Yii2 自動載入

先看一下 Yii2的控制器書寫規則函數

controllers\IndexController.php

<?php 
/**
 * 自動載入機制
 */
//==========================================================================================
//聲明本身的命名空間 此命名空間下的類皆歸屬於此命名空間管理
//==========================================================================================
namespace app\controllers;

//==========================================================================================
//use 聲明其實只是爲 yii\web\Controller 定義一個別名:Controller 方便咱們再上下文中使用
//而並不是像 C/C++的include JAVA的import將導入的文件加載進來(固然php爲解釋語言 不存在預編譯這一步)
//==========================================================================================
use yii\web\Controller;

//==========================================================================================
//IndexController的完整類名其實爲 app\controller\IndexController
//Controller 爲 yii\web\Controller php 解釋到此點纔會去加載此類
//==========================================================================================
class IndexController extends Controller
{

    public function actionIndex()
    {
        //不使用 use 提早聲明 手寫完整的類名
        $model = new \app\models\EntryForm();//注意當前上下文中存在命名空間 因此要從根命名空間 '\' 開始
    }
}

一、某命名空間下的類 的完整名稱爲 namespace\className,當在某命名空間上下文中訪問其它命名空間下的類時,咱們可使用 use 作別名化,或者使用此類的完整名稱,但要以 '\' 根命名空間開頭,不然解釋器會認爲你是在當前命名空間上下文中調用,即 foo\bar 方式會以 currentNamespace\foo\bar的方式去加載

命名空間與linux文件系統很類似,'\' 表明根,不以根開始的皆認爲以當前命名空間爲基點

二、use 只是給你使用的類定義短別名,use foo\bar 後則new bar() 即new  \foo\bar(),還有個小技巧,當咱們同時引用不一樣命名空間下的類名相同的類時可使用 as 爲其定義一個新別名

use foo\bar\sameName as classA;
use bar\foo\sameName as classB;

new classA(); // new \foo\bar\sameName;
new classB(); // new \bar\foo\sameName;

三、當咱們經過 入口文件 加載參數配置 實例化一個應用主體 加載路由組件解析請求 分派控制器調用方法時,期間會調用其餘的類,好比 

use yii\web\Controller;

系統便會去經過自動載入函數作最一次載入嘗試,若仍加載不到此類則報錯

下面咱們看下 Yii2 從入口文件開始一個應用實體後註冊自動載入函數的流程

index.php

入口文件載入配置和系統框架時會使用require調用,由於如今尚未註冊自動加載函數

載入 Yii bootstrap 文件時便經過 spl_autoload_register 註冊了自動載入函數 

Yii.php

Yii2的自動載入函數

繼承至 BaseYii 它要作的就是根據你命名空間類型的類名去映射爲此類所在的文件路徑

好比 yii\web\Controller類會根據 yii 而映射到  YII2_PATH . '/web/Controller.php' 文件中,而這個文件則是命名空間爲 yii\web 的 Controller 類,將此文件載入便可訪問 yii\web\Controller

而咱們本身編寫的控制器或者模型則訪問時爲 'app\controllers\IndexController' 'app\models\EntryForm'

則 autoload 函數會根據 app 爲 映射關鍵字將其定位到 controllersmodels 文件夾下從而讀取對應的文件便可載入相應的類,這也是爲何 類名 與 文件名 相互對應的緣由所在,若不存在對應,則你只能經過固定的 require 某個文件去加載你寫在其中的類了 

擴展本身的類庫

咱們能夠經過Yii2的自動載入機制靈活的歸類咱們本身寫的工具類等,好比我想建立一個本身的組件庫

你能夠定義一個  yii\tools 命名空間的類文件 MyTools.php,好比

<?php

namespace yii\tools;

class MyTools {
//.........
}
?>

放入 vendor\yiisoft\yii2\tools 文件夾下,

經過

namespace app\controllers;

// yii一級命名空間 則 映射到 YII_PATH 下
// 根據 tools\MyTools 定位到 YII_PATH 下的 tools文件夾下的 MyTools.php
use yii\tools\MyTools;
use yii\web\Controller;

class MyController extends Controller
{

}

固然你也能夠在你的項目目錄下新建一個 tools 文件夾 把 MyTools.php 放進去,將裏面的命名空間改成 app\tools 便可,系統會根據 app 映射到項目根目錄 經過 tools\MyTools 把 tools文件夾下的 MyTools.php文件載入 即載入了 MyTools 類

3、剖析TP的自動載入

thinkphp的自動加載規則也同樣,只不過 tp autoload函數並無像 Yii2 basic 版預先定義一個項目根目錄的映射規則,  Yii2則是以 app 頂級命名空間爲默認的應用命名空間,yii頂級命名空間做爲框架命名空間,因此你只要把本身的類歸屬到項目根目錄(app下)或 YII_PATH(框架路徑) 下,而後放對文件路徑便可,

tp的話有的你本身想tp能夠在 APP_PATH 下放多個  module ,像其預先定義的 Home ,或者你能夠 BIND_MODULE來幫定義一個本身的模塊,這樣在經過入口文件載入的應用實體作路由時便能判斷你請求的是哪一個模塊下的控制器和方法

tp有幾個系統佔用的頂級命名空間

Think Org Behavior Com Vendor

而你本身的則會以 APP_PATH 爲根目錄進行加載,好比 Home\Controller\IndexController.class.php,當你訪問 Index 時路由解析出來的類爲 Home\Controller\IndexController,自動載入函數則根據 Home 非系統命名空間而定位到你的APP_PATH下進行加載,因此TP也能夠本身定義的  AUTOLOAD_NAMESAPCE作自定義擴展

'AUTOLOAD_NAMESAPCE' => [
    'Tools' => APP_PATH . 'Vendor\Tools'
]

這樣便把 Tools 頂級命名空間註冊到了自動載入函數中,當咱們

use Tools\Extension\MyTools 時

傳入 autoload 的 $class 即爲 Tools\Extension\MyTools,獲得的 $name 其實爲一級命名空間名 這裏爲 Tools,Tools 不符合第一條件,在 else 中讀取自定義的  AUTOLOAD_NAMESAPCE,發現咱們有設置 鍵名爲 Tools 的成員

便使用 dirname(鍵值)獲得 APP_PATH . 'Vendor',我是以爲這裏 dirname 寫的有些雞肋....因此便成功的映射定位出 Tools一級命名空間所在的文件目錄爲 APP_PATH . 'Vendor' 下,在與完整的類名 Tools\Extension\MyTools 拼接上 EXT便可定位到類文件,加載便可。

相關文章
相關標籤/搜索