|
命名空間概述
在php中,命名空間用來解決在編寫類庫或應(yīng)用程序時創(chuàng)建可重用的代碼如類或函數(shù)時碰到的兩類問題:
用戶編寫的代碼與php內(nèi)部的類/函數(shù)/常量或第三方類/函數(shù)/常量之間的名字沖突。
為很長的標(biāo)識符名稱(通常是為了緩解第一類問題而定義的)創(chuàng)建一個別名(或簡短)的名稱,提高源代碼的可讀性。
php 命名空間提供了一種將相關(guān)的類、函數(shù)和常量組合到一起的途徑。下面是一個說明 php 命名空間語法的示例:
定義命名空間
雖然任意合法的php代碼都可以包含在命名空間中,但只有三種類型的代碼受命名空間的影響,它們是:類,函數(shù)和常量。命名空間通過關(guān)鍵字namespace 來聲明。如果一個文件中包含命名空間,它必須在其它所有代碼之前聲明命名空間。另外,與php其它的語言特征不同,同一個命名空間可以定義在多個文件中,即允許將同一個命名空間的內(nèi)容分割存放在不同的文件中。當(dāng)然你也可以在同一個文件中定義多個命名空間。
復(fù)制代碼 代碼如下:
namespace MyProject;
class MyClass
{
#code...
}
定義子命名空間:與目錄和文件的關(guān)系很象,php 命名空間也允許指定層次化的命名空間的名稱。因此,命名空間的名字可以使用分層次的方式定義:
復(fù)制代碼 代碼如下:
namespace MyProject/helper/http;
class MyClass
{
#code...
}
在同一個文件中定義多個命名空間:在同一個文件中聲明多個命名空間有兩種方式,不過在實際編程實踐中,非常不提倡在同一個文件中定義多戈命名空間。這種方式的主要用于將多個 php 腳本合并在同一個文件中。下面列出第一種方法。
復(fù)制代碼 代碼如下:
namespace MyProject/helper/http;
class MyClass
{
#code...
}
namespace MyProject/helper/request;
class MyClass
{
#code...
}
不過強烈不建議使用這種方法,可以參考下面的大括號定義法:
復(fù)制代碼 代碼如下:
namespace MyProject/helper/http;
{
class MyClass
{
#code...
}
}
namespace MyProject/helper/request;
{
class MyClass
{
#code...
}
}
php 命名空間中的元素使用
在討論如何使用命名空間之前,必須了解 php 是如何知道要使用哪一個命名空間中的元素的。類名可以通過三種方式引用:
非限定名稱,或不包含前綴的類名稱,例如 $a=new foo(); 或 foo::staticmethod();。如果當(dāng)前命名空間是 currentnamespace,foo 將被解析為 currentnamespace/foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,則 foo 會被解析為foo。 警告:如果命名空間中的函數(shù)或常量未定義,則該非限定的函數(shù)名稱或常量名稱會被解析為全局函數(shù)名稱或常量名稱。詳情參見 使用命名空間:后備全局函數(shù)名稱/常量名稱。
限定名稱,或包含前綴的名稱,例如 $a = new subnamespace/foo(); 或 subnamespace/foo::staticmethod();。如果當(dāng)前的命名空間是 currentnamespace,則 foo 會被解析為 currentnamespace/subnamespace/foo。如果使用 foo 的代碼是全局的,不包含在任何命名空間中的代碼,foo 會被解析為subnamespace/foo。
完全限定名稱,或包含了全局前綴操作符的名稱,例如, $a = new /currentnamespace/foo(); 或 /currentnamespace/foo::staticmethod();。在這種情況下,foo 總是被解析為代碼中的文字名(literal name)currentnamespace/foo。
使用命名空間:別名/導(dǎo)入
允許通過別名引用或?qū)胪獠康耐耆薅Q,是命名空間的一個重要特征。php 命名空間支持 有兩種使用別名或?qū)敕绞剑簽轭惷Q使用別名,或為命名空間名稱使用別名。在php中,別名是通過操作符 use 來實現(xiàn)的。
注意php不支持導(dǎo)入函數(shù)或常量。
復(fù)制代碼 代碼如下:
namespace foo;
use My/Full/Classname as Another;
// 下面的例子與 use My/Full/NSname as NSname 相同
use My/Full/NSname;
// 導(dǎo)入一個全局類
use /ArrayObject;
名稱解析規(guī)則
在說明名稱解析規(guī)則之前,我們先看一些重要的定義:
非限定名稱Unqualified name:名稱中不包含命名空間分隔符的標(biāo)識符,例如 Foo
限定名稱Qualified name:名稱中含有命名空間分隔符的標(biāo)識符,例如 Foo/Bar
完全限定名稱Fully qualified name:名稱中包含命名空間分隔符,并以命名空間分隔符開始的標(biāo)識符,例如 /Foo/Bar。 namespace/Foo 也是一個完全限定名稱。
名稱解析遵循下列規(guī)則:
對完全限定名稱的函數(shù),類和常量的調(diào)用在編譯時解析。例如 new /A/B 解析為類 A/B。
所有的非限定名稱和限定名稱(非完全限定名稱)根據(jù)當(dāng)前的導(dǎo)入規(guī)則在編譯時進行轉(zhuǎn)換。例如,如果命名空間 A/B/C 被導(dǎo)入為 C,那么對 C/D/e() 的調(diào)用就會被轉(zhuǎn)換為 A/B/C/D/e()。
在命名空間內(nèi)部,所有的沒有根據(jù)導(dǎo)入規(guī)則轉(zhuǎn)換的限定名稱均會在其前面加上當(dāng)前的命名空間名稱。例如,在命名空間 A/B 內(nèi)部調(diào)用 C/D/e(),則 C/D/e() 會被轉(zhuǎn)換為 A/B/C/D/e() 。
非限定類名根據(jù)當(dāng)前的導(dǎo)入規(guī)則在編譯時轉(zhuǎn)換(用全名代替短的導(dǎo)入名稱)。例如,如果命名空間 A/B/C 導(dǎo)入為C,則 new C() 被轉(zhuǎn)換為 new A/B/C() 。
在命名空間內(nèi)部(例如A/B),對非限定名稱的函數(shù)調(diào)用是在運行時解析的。例如對函數(shù) foo() 的調(diào)用是這樣解析的:
1) 在當(dāng)前命名空間中查找名為 A/B/foo() 的函數(shù)
2) 嘗試查找并調(diào)用 全局(global) 空間中的函數(shù) foo()。
在命名空間(例如A/B)內(nèi)部對非限定名稱或限定名稱類(非完全限定名稱)的調(diào)用是在運行時解析的。下面是調(diào)用 new C() 及 new D/E() 的解析過程: new C()的解析:
在當(dāng)前命名空間中查找A/B/C類。
嘗試自動裝載類A/B/C。
new D/E()的解析:
在類名稱前面加上當(dāng)前命名空間名稱變成:A/B/D/E,然后查找該類。
嘗試自動裝載類 A/B/D/E。
為了引用全局命名空間中的全局類,必須使用完全限定名稱 new /C()。
Example 名稱解析示例
復(fù)制代碼 代碼如下:
<?php
namespace A;
use B/D, C/E as F;
// 函數(shù)調(diào)用
foo(); // 首先嘗試調(diào)用定義在命名空間"A"中的函數(shù)foo()
// 再嘗試調(diào)用全局函數(shù) "foo"
/foo(); // 調(diào)用全局空間函數(shù) "foo"
my/foo(); // 調(diào)用定義在命名空間"A/my"中函數(shù) "foo"
F(); // 首先嘗試調(diào)用定義在命名空間"A"中的函數(shù) "F"
// 再嘗試調(diào)用全局函數(shù) "F"
// 類引用
new B(); // 創(chuàng)建命名空間 "A" 中定義的類 "B" 的一個對象
// 如果未找到,則嘗試自動裝載類 "A/B"
new D(); // 使用導(dǎo)入規(guī)則,創(chuàng)建命名空間 "B" 中定義的類 "D" 的一個對象
// 如果未找到,則嘗試自動裝載類 "B/D"
new F(); // 使用導(dǎo)入規(guī)則,創(chuàng)建命名空間 "C" 中定義的類 "E" 的一個對象
// 如果未找到,則嘗試自動裝載類 "C/E"
new /B(); // 創(chuàng)建定義在全局空間中的類 "B" 的一個對象
// 如果未發(fā)現(xiàn),則嘗試自動裝載類 "B"
new /D(); // 創(chuàng)建定義在全局空間中的類 "D" 的一個對象
// 如果未發(fā)現(xiàn),則嘗試自動裝載類 "D"
new /F(); // 創(chuàng)建定義在全局空間中的類 "F" 的一個對象
// 如果未發(fā)現(xiàn),則嘗試自動裝載類 "F"
// 調(diào)用另一個命名空間中的靜態(tài)方法或命名空間函數(shù)
B/foo(); // 調(diào)用命名空間 "A/B" 中函數(shù) "foo"
B::foo(); // 調(diào)用命名空間 "A" 中定義的類 "B" 的 "foo" 方法
// 如果未找到類 "A/B" ,則嘗試自動裝載類 "A/B"
D::foo(); // 使用導(dǎo)入規(guī)則,調(diào)用命名空間 "B" 中定義的類 "D" 的 "foo" 方法
// 如果類 "B/D" 未找到,則嘗試自動裝載類 "B/D"
/B/foo(); // 調(diào)用命名空間 "B" 中的函數(shù) "foo"
/B::foo(); // 調(diào)用全局空間中的類 "B" 的 "foo" 方法
// 如果類 "B" 未找到,則嘗試自動裝載類 "B"
// 當(dāng)前命名空間中的靜態(tài)方法或函數(shù)
A/B::foo(); // 調(diào)用命名空間 "A/A" 中定義的類 "B" 的 "foo" 方法
// 如果類 "A/A/B" 未找到,則嘗試自動裝載類 "A/A/B"
/A/B::foo(); // 調(diào)用命名空間 "A/B" 中定義的類 "B" 的 "foo" 方法
// 如果類 "A/B" 未找到,則嘗試自動裝載類 "A/B"
?>
php技術(shù):PHP 面向?qū)ο蟪绦蛟O(shè)計(oop)學(xué)習(xí)筆記 (五) - PHP 命名空間,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。