PHP名稱空間與PSR-4自動載入

蜻蜓隊長dragonfly429發表於2019-03-11

目錄

  • 名稱空間
    • 概念?解決了什麼問題?
    • 定義
    • 使用和解析規則
    • 其他
  • 自動載入
    • 概念?解決了什麼問題?
    • PSR-4

名稱空間

概念

名稱空間是類似於檔案系統的一個虛擬容器,可以用於類(包括抽象類和traits)、介面、函式、常量。

類似於檔案系統,可以把類放進一個多層級的名稱空間,主要是解決類名的命名衝突問題。

定義名稱空間

<?php
namespace haha\hehe\heihei
const CON1 = 10;
function run(){
 //....   
}
class ClassA{
 //....   
}

- 用namespace宣告一個名稱空間,表明接下去的程式碼屬於這個名稱空間
- 宣告語句必須是檔案第一句
- 也可以在後面加個大括號來顯式表明這個名稱空間範圍,這樣可以做到一個檔案中有多個名稱空間,但是非常不建議這樣,沒必要,沒有可讀性,一般就是這樣使用,也不用大括號


複製程式碼

使用名稱空間

沒有名稱空間之前,就是

require('\src\ClassA.php'); 
new ClassA();
複製程式碼

有了名稱空間後

//現在都配合自動載入,不require
new \haha\hehe\heihei\ClassA();
複製程式碼

如果多次要new一個物件,覺得累贅,可以這樣

use haha\hehe\heihei\ClassA; //注意最前面的斜槓可以省略
$obj1 = new ClassA();
$obj2 = new ClassA();
$obj3 = new ClassA();
複製程式碼

這叫匯入類,還可以給類起別名

use haha\hehe\heihei\ClassA as A; //注意最前面的斜槓可以省略
new A();
複製程式碼

命名解析規則

  • 解析名稱空間跟檔案系統的路徑解析是一樣的,有相對路徑和絕對路徑兩種。
  • 絕對路徑在名稱空間中叫“完全限定名”,檔案系統的根目錄是\,名稱空間也是\,以\開頭的就是完全限定名
  • 相對路徑在名稱空間叫“非限定名”(只有類名),“限定名”(有路徑,但是不是從\開始),總之不是\開頭的
  • 絕對路徑(完全限定名)的解析沒啥的,都從\開始,明明白白
  • 非完全限定的,解析的時候就會加上當前名稱空間名稱
<?php
namespace My\n1amespace

new  \app\controller\User(); //完全限定名 很清楚
new  User();                 //就解析為My\n1amespace\User
new  haha\User();            //就解析為My\n1amespace\haha\User
複製程式碼

其他

__NAMESPACE__常量

<?php
namespace My\n1amespace{
    echo 'inside'.__NAMESPACE__; //My\n1amespace 如果沒有名稱空間就是''
}
複製程式碼

自動載入

概念

如果你需要用一個類,那你得先require,當你用一個類的時候,可能無所謂,當你的類用的多的時候,就很麻煩了。

自動載入1.0,在名稱空間出現之前,就有自動載入,與原理就是,你可以告訴php直譯器一個函式(用__autoload()或者spl_autoload_register()註冊),當你用一個類,而又沒有匯入的時候,系統就會執行這個函式。

自動載入2.0,在名稱空間出現後,PSR-4規定了一個基於名稱空間的統一的自動載入規範

PSR-4

其實問題的核心是,如何從名稱空間,得到實際的檔案位置?

兩點

  • 通過自動載入函式 將根名稱空間或者較高階別的名稱空間 與 目錄一一關聯
  • 從根目錄或者特定的目錄往下,命名層級與目錄層級一一對應

看一個例子就知道

spl_autoload_register(function($class_name){
    //名稱空間字首
    $prefixe = '\Foo\\Bar';
    //基目錄
    $base_dir = __DIR__.'/src/';
    //匹配是否 是在尋找這個名稱空間下的類
    $len = strlen($prefix);
    if(strncmp($prefix,$class_name,$len)!==0){
        return ;
    }
    //將名稱空間轉換為目錄位置
    $relative_class = substr($class.$len);
    $file = $base_dir . str_replace('\\','/',$relative_class).'.php';
    if(file)existst($file)){
        require($file);
    }
})
複製程式碼

參考資料


  1. php手冊
  2. modern PHP 對應章節

相關文章