在 PHP V5.3 中引入的名稱空間是為 PHP 類、常量和函數提供上下文的一種方式,從而可以將使用相同名稱的元素看作是惟一的。惟一的名稱避免了命名沖突,當兩個類或函數使用相同的名稱時就會發生這種情況。有時這些 PHP 類表示現實世界中的相同對象,但它們的行為是完全不同的。名稱空間能夠確保您擁有正確的 PHP 類、常量或函數,並且要使用您的 PHP 類的人能夠確保他們使用了正確的類。
代碼中的名稱空間就像現實世界中的上下文。考慮一個表示現實世界中的汽車對象的類。例如,通過 Internet 銷售汽車的公司使用的 Automobile
類的行為可能與保險銷售公司使用的 Automobile
類完全不同。
作為應用程序開發人員,您可能使用其他人編寫的組件。您不能保證其他人永遠不使用您已經使用的類名,但這些類的行為卻大相徑庭。在出現名稱空間之前,PHP 開發人員通常將上下文構建到類名中,例如 My_Enterprise_Person
或 XML_Validator
。
清單 1 顯示了一個位於名稱空間中的類。
<?php
namespace IBM;
class Foo {
...
}
?>
下面給出了一個例子,展示了如何在名稱空間中引用類。
<?php
$foo = new \IBM\Foo();
?>
在向所有類添加名稱空間之前定義一個名稱空間策略是個不錯的主意。盡管在某種程度上也可以不斷地構建名稱空間,但最好為名稱空間確定一個通用結構,以方便名稱空間的組織,並減少以後可能需要的修改。只要正確使用,除了提供上下文之外,名稱空間還可以用來組織 PHP 代碼。
其他語言(比如 Java™ 和 C#)在很久以前就使用名稱空間。在選擇名稱空間命名方式上,我使用的約定類似於這些語言的約定,因為許多開發人員都對此比較熟悉,便於他們理解。不過,與 Java 語言不同的是,PHP 中的名稱空間與類所在的目錄之間沒有聯系。您可以給類、函數或常量選擇任意的名稱空間。您甚至可以對一個文件使用多個名稱空間。同時,PHP 名稱空間也不同於 C#,您可以對類以外的函數或常量使用名稱空間。
頂級名稱空間
如果您為某個組織構建名稱空間,您可以使用組織名作為頂級域。一般情況下,使用組織名稱創建頂級名稱空間已經足以為 PHP 代碼提供上下文,以及避免命名沖突,除非該組織編寫大量用途不一的應用程序。
清單 3 的示例顯示了如何聲明頂級名稱空間。
<?php
namespace IBM;
...
?>
次級名稱空間
次級名稱空間 是頂級名稱空間內部的名稱空間。當頂級名稱空間還不足以為 PHP 類建立上下文時,它們提供進一步說明。
在創建次級名稱空間時,不要憑一時的興趣而過多地創建,這很重要。隨著次級名稱空間的增多,組織和引用它們就會變得越來越困難。如果您希望名稱空間發揮雙重作用,即避免命名沖突和組織 PHP 代碼,那麼就要更加注意這點了。
在決定為了方便組織代碼應該向另一個名稱空間引入多少個次級名稱空間時,我嘗試將該數量限制為 7 個(上下浮動不超過 2),以利用數字 7 更加容易記住這個優勢。這並不總是奏效的,但我將它作為一個指導原則,以確保不將名稱空間劃分為過多的次級名稱空間。
清單 4 的示例顯示了在頂級名稱空間中聲明次級名稱空間。
<?php
namespace IBM\DeveloperWorks;
...
?>
反斜槓(\
)將次級名稱空間 “developerWorks” 與頂級名稱空間 “IBM” 分開。
在聲明次級名稱空間時,您可以使用兩個常見技巧,或同時使用它們。獲取名稱空間的常見地方是項目名或應用程序名;另一個地方是域名。
通過項目定義
如果您使用組織名作為頂級名稱空間,並且想通過次級名稱空間來進一步提供上下文,那麼可以使用項目名或應用程序名作為次級名稱空間。例如,如果您構建一個稱為 Greeter 的新應用程序(用於獲取用戶的名稱並問候他們),那麼清單 5 中的名稱空間將為稱為 Prompt
的類提供完整的上下文。
<?php
namespace IBM\Greeter;
class Prompt {
...
}
?>
由於 Prompt
可能是多個應用程序或庫的類名,所以為該名稱空間添加組織名和項目名能夠讓這個 Prompt
類與其他同名的類區分開來。
通過域定義
使用域名是另一種選擇次級名稱空間的常見方式,如 清單 6 所示。它也可以用於項目名之後,是否使用取決於您對可重用性的計劃(見 “根據可重用性命名”)。
域 是對更大的問題域的一組分類。域的一個例子是在更大型的應用程序中處理帳戶、客戶和產品的 “Account”、“Customers” 或 “Products”。
<?php
namespace IBM\MyApp\Account;
class Address {
...
}
?>
根據可重用性命名
除了應用支持可重用性的模塊概念之外,類和名稱空間的命名方式也能夠實現可重用性。有時不良的命名方式會損害可重用性,因為不佳的名稱暗示著類僅能用於特定目的。同樣,錯誤地應用名稱空間可能會不必要地局限類的使用范圍,讓它們的重用變得困難。
在使用組織名的頂級名稱空間中,應該保留 “Common”、“Core”、“Lib” 等可跨應用程序重用的名稱空間。一個常見的例子是驗證,其中針對整個企業的庫存單位(SKU)、帳號或發票號的規則是一樣的,從而獲得合適的規則和長度。對於 Validator 類,類似清單 7 的名稱空間是不錯的選擇。
<?php
namespace MyCompany\Common\Validation;
class NotNullValidator {
...
}
?>
在這裡,組織名用作頂級域(“MyCompany”)。“Common” 名稱空間用作項目。即使在編寫這個類的同時也許正在編寫一個特定的應用程序,該類一樣可以在組織的任何項目中使用。最後,“Validation” 用作類的域。
使用別名
盡管名稱空間能夠幫助您組織類並避免命名約定,但其缺點是名稱過長。幸運的是,PHP 支持使用別名,因此可以在代碼中使用更短的別名。清單 8 提供了一個示例。
<?php
use MyCompany\Common\Validation as Validators;
?>
命名約定
名稱空間命名使用單詞首字母大寫或 PASCAL 命名約定,這與其他 PHP 約定一樣,比如 PHP Extension 和 Application Repository (PEAR) 包命名和文件名。例如,清單 9 中的名稱空間比 清單 10 中的名稱空間要好。
<?php
namespace MyNamespace;
?>
避免使用與其他 PHP 約定沖突的命名和大小寫約定。
<?php
namespace mynamespace;
...
?>
結束語
PHP 中的名稱空間能夠用於組織代碼、避免命名沖突以及為類、函數和常量提供上下文。在名稱空間中使用模式或約定讓代碼更易於理解,並且更易於引用和使用。