PHP強化之23 - 命名空間

一、簡介

什么是命名空間?從廣義上來說,命名空間是一種封裝事物的方法。例如,在操作系統(tǒng)中目錄用來將相關(guān)文件分組,對于目錄中的文件來說,目錄就扮演了命名空間的角色。

而在PHP當中,命名空間就扮演了目錄的角色,而PHP代碼中的類(包括抽象類和traits)、接口、函數(shù)和常量則就扮演了文件的角色。

PHP 中的命名空間(namespace)是在PHP 5.3中加入的,主要是為了解決用戶編寫的代碼與PHP內(nèi)部的類/函數(shù)/常量或第三方類/函數(shù)/常量之間的名字沖突。其作用是按照一種虛擬的層次結(jié)構(gòu)組織PHP代碼,這種層次結(jié)構(gòu)類似操作系統(tǒng)中文件系統(tǒng)的目錄結(jié)構(gòu)?,F(xiàn)代的PHP組件和框架都放在各自全局唯一的廠商命名空間中,以免與其他廠商使用常見類名沖突。

二、命名空間的定義

默認情況下,所有常量、類和函數(shù)名都放在全局空間下,就和PHP支持命名空間之前一樣。

1、聲明命名空間

命名空間通過關(guān)鍵字namespace 來聲明。如果一個文件中包含命名空間,它必須在其它所有代碼之前聲明命名空間,除了一個以外:declare關(guān)鍵字。語法格式如下;

< ?php
// 定義代碼在 'MyProject' 命名空間中
namespace MyProject;

另外,與PHP其它的語言特征不同,同一個命名空間可以定義在多個文件中,即允許將同一個命名空間的內(nèi)容分割存放在不同的文件中。

你也可以在同一個文件中定義不同的命名空間代碼,但非常不提倡這一種做法。

2、聲明子命名空間

與目錄和文件的關(guān)系很象,PHP 命名空間也允許指定層次化的命名空間的名稱。因此,命名空間的名字可以使用分層次的方式定義:

<?php
namespace MyProject\Sub\Level;

三、命名空間的使用

在討論如何使用命名空間之前,必須了解 PHP 是如何知道要使用哪一個命名空間中的元素的??梢詫?PHP 命名空間與文件系統(tǒng)作一個簡單的類比。在文件系統(tǒng)中訪問一個文件有三種方式:

1)相對文件名形式如foo.txt。它會被解析為 currentdirectory/foo.txt,其中 currentdirectory 表示當前目錄。因此如果當前目錄是 /home/foo,則該文件名被解析為/home/foo/foo.txt。
2)相對路徑名形式如subdirectory/foo.txt。它會被解析為 currentdirectory/subdirectory/foo.txt。
3)絕對路徑名形式如/main/foo.txt。它會被解析為/main/foo.txt。

PHP 命名空間中的元素使用同樣的原理。例如,類名可以通過三種方式引用:

1、Unqualified name(非限定名稱)

名稱中不包含命名空間分隔符的標識符。

例如:$a=new foo();foo::staticmethod();。如果當前命名空間是currentnamespace,foo 將被解析為currentnamespace\foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,則 foo 會被解析為foo

警告:對于函數(shù)和常量來說,如果當前命名空間中不存在該函數(shù)或常量,PHP 會退而使用全局空間中的函數(shù)或常量。

2、Qualified name(限制名稱)

名稱中含有命名空間分隔符的標識符。

例如:$a = new subnamespace\foo();subnamespace\foo::staticmethod();。如果當前的命名空間是currentnamespace,則 foo 會被解析為currentnamespace\subnamespace\foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,foo 會被解析為subnamespace\foo。

3、Fully qualified name(完全限制名稱)

名稱中包含命名空間分隔符,并以命名空間分隔符開始的標識符,例如\Foo\Bar。namespace\Foo也是一個完全限定名稱。

例如:$a = new \currentnamespace\foo();\currentnamespace\foo::staticmethod();。在這種情況下,foo 總是被解析為代碼中的文字名(literal name)currentnamespace\foo

官方例子:

file1.php 文件代碼:

namespace  Foo\Bar\subnamespace;

const  FOO = 1;
function  foo(){}
class  foo{
  static function staticmethod(){}
}

file2.php文件代碼:

namespace  Foo\Bar;
include 'file1.php';

const FOO = 2;
function foo(){}
class foo{
  static function staticmethod(){}
}

/* 非限定名稱 */
foo(); // 解析為函數(shù): Foo\Bar\foo
foo::staticmethod(); // 解析為類 Foo\Bar\foo的靜態(tài)方法staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO

/* 限定名稱 */
subnamespace\foo(); // 解析為函數(shù) Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析為類Foo\Bar\subnamespace\foo的方法staticmethod
echo subnamespace\FOO; // 解析為常量 Foo\Bar\subnamespace\FOO

/* 完全限定名稱 */
\Foo\Bar\foo(); // 解析為函數(shù) Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析為類 Foo\Bar\foo的方法 staticmethod
echo \Foo\Bar\FOO; // 解析為常量 Foo\Bar\FOO

注意:訪問任意全局類、函數(shù)或常量,都可以使用完全限定名稱,例如\strlen()\Exception\INI_ALL。

四、使用命名空間:別名/導入

所有支持命名空間的PHP版本支持三種別名或?qū)敕绞剑簽轭惷Q使用別名、為接口使用別名或為命名空間名稱使用別名。PHP 5.6開始允許導入函數(shù)或常量或者為它們設(shè)置別名。

1、使用use操作符導入/使用別名

<?php
namespace foo;
use My\Full\Classname as Another;

// 下面的例子與 use My\Full\NSname as NSname 相同
use My\Full\NSname;

// 導入一個全局類
use ArrayObject;

// 導入一個函數(shù)  importing a function (PHP 5.6+)
use function My\Full\functionName;

// 為一個函數(shù)設(shè)置別名   aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// 導入一個常量   importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;

$obj = new namespace\Another; // 實例化 foo\Another 對象
$obj = new Another; // 實例化 My\Full\Classname 對象
NSname\subns\func(); // 調(diào)用函數(shù) My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 實例化 ArrayObject 對象
// 如果不使用 "use \ArrayObject" ,則實例化一個 foo\ArrayObject 對象
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT
?>

2、 一行中包含多個use語句

<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 實例化 My\Full\Classname 對象
NSname\subns\func(); // 調(diào)用函數(shù) My\Full\NSname\subns\func
?>

為了代碼更易于閱讀和糾錯,不推薦使用以上語法,建議一行寫一個use語句。

五、注意事項

  • 如果一個文件中包含命名空間,它必須在其它所有代碼之前聲明命名空間。除了一個以外:declare關(guān)鍵字。

  • 雖然任意合法的PHP代碼都可以包含在命名空間中,但只有以下類型的代碼受命名空間的影響,它們是:類(包括抽象類和traits)、接口、函數(shù)和常量。

  • PHP支持兩種抽象的訪問當前命名空間內(nèi)部元素的方法,__NAMESPACE__魔術(shù)常量和namespace關(guān)鍵字。
    常量__NAMESPACE__的值是包含當前命名空間名稱的字符串。在全局的,不包括在任何命名空間中的代碼,它包含一個空的字符串。

  • 關(guān)鍵字namespace可用來顯式訪問當前命名空間或子命名空間中的元素。它等價于類中的self操作符。

  • PHP命名空間與操作系統(tǒng)的物理文件系統(tǒng)不同,這是一個虛擬概念,沒必要和文件系統(tǒng)中的目錄結(jié)構(gòu)完全對應(yīng)。雖然如此,但是大多數(shù)PHP組件為了兼容廣泛使用的PSR-4自動加載器標準,會把子命名空間放到文件系統(tǒng)的子目錄中。

六、參考

  1. PHP官方手冊:http://php.net/manual/zh/language.namespaces.php

  2. 《Modern PHP》Josh Lockhart 著 安道 譯

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容