提出
在名稱空間提出之前,不同的元件很容易碰到命名的衝突,例如 Request
、Response
等常見的命名。PHP 在 5.3 後提出了名稱空間用來解決元件之間的命名衝突問題,主要參考了檔案系統的設計:
- 同一個目錄下不允許有相同的檔名 - 同一個名稱空間下不允許有相同的類;
- 不同的目錄可以有同名檔案 - 不同的名稱空間可以有相同的類;
定義
使用 namespace
關鍵字來定義一個名稱空間。其中,頂層名稱空間通常為廠商名,不同開發者的廠商名稱空間是唯一的。名稱空間不需要與檔案目錄一一對應,但是最好遵守 PSR-4 規範。
<?php
namespace Symfony\Component\HttpFoundation;
class Request {
}
名稱空間必須在所有程式碼之前宣告,唯一的例外就是 declare
關鍵字。
<?php
declare(strict_types=1);
namespace App;
名稱空間內可包含任意 PHP 程式碼,但是僅對類(包括抽象類和 Trait)、介面、函式和常量這四種型別生效。
<?php
namespace MyProject;
const CONNECT_OK = 1;
class FOO {}
interface Foo{}
function foo() {}
使用
使用 use
關鍵字來引入名稱空間
<?php
namespace App;
use Symfony\Component\HttpFoundation\Request;
use Foo\Bar;
class Test {
public function run()
{
$bar = new Bar();
}
}
定義和使用推薦遵循 PSR-2 的規範
namespace
之後必須存在一個空行;- 所有
use
宣告必須位於namespace
宣告之後; - 每條
use
宣告必須只有一個use
關鍵字。use
語句塊之後必須存在一個空行。
當 use
引入的類出現同名時,可使用 as
來定義別名
<?php
namespace App;
use Foo\Bar as BaseBar;
class Bar extends BaseBar {
}
限定符
除了使用 use
外,還可以直接使用 \
限定符來進行解析,規則很簡單:如果含有 \
字首則代表從全域性名稱空間開始解析,否則則代表從當前名稱空間開始解析。
<?php
namespace App;
\Foo\Bar\foo(); // 解析成 \Foo\Bar\foo();
Foo\Bar\foo(); // 解析成 App\Foo\Bar\foo();
此規則也適用於函式、常量等
$a = \strlen('hi'); // 呼叫全域性函式 strlen
$b = \INI_ALL; // 訪問全域性常量 INI_ALL
$c = new \Exception('error'); // 例項化全域性類 Exception
有兩個需要特別注意的地方:
對於函式和常量而言,如果當前名稱空間不存在,則會自動去全域性名稱空間去尋找,因此可省略 \
字首。對於類而言,如果當前名稱空間解析不到,不會去全域性空間尋找,因此,不可省略 \
$a = strlen('hi');
$b = INI_ALL;
$c = new Exception('error'); // 錯誤
$c = new \Exception('error'); // 正確
當動態呼叫名稱空間時,該名稱空間始終會被當成是全域性名稱空間,因此可以省略字首 \
$class1 = 'Foo\Bar';
$object1 = new $class1; // 始終被解析成 \Foo\Bar
在內部訪問名稱空間
PHP 支援兩種抽象的訪問當前名稱空間內部元素的方法,__NAMESPACE__
魔術常量和 namespace
關鍵字。
__NAMESPACE__
常量的值是包含當前名稱空間名稱的字串,如果是在全域性名稱空間,則返回空字串。
<?php
namespace MyProject;
function get($classname)
{
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
關鍵字 namespace
可用來顯式訪問當前名稱空間或子名稱空間中的元素。它等價於類中的 self
運算子
namespace App;
use blah\blah as mine;
blah\mine(); // App\blah\mine()
namespace\blah\mine(); // App\blah\mine()
namespace\func(); // App\func()
namespace\sub\func(); // App\sub\func()
namespace\cname::method(); // App\cname::method()
$a = new namespace\sub\cname(); // App\sub\cname
$b = namespace\CONSTANT; // App\CONSTANT
轉義 \
符號
此外,推薦對所有的 \
進行轉義,避免出現不可預期的後果
$class = "dangerous\name"; // \n 被解析成換行符
$obj = new $class;
$class = 'dangerous\name'; // 正確,但是不推薦
$class = 'dangerous\\name'; // 推薦
$class = "dangerous\\name"; // 推薦
參考資料
本作品採用《CC 協議》,轉載必須註明作者和本文連結