PHP中的命名空間用來解決大型PHP庫(libraries)中作用域的問題,在PHP中,所有的類定義都是全局的,所以,當一個庫的作者為這處庫創建多種應用或公共API類的時候,他必須清楚其他庫中相似功能是否存在的可能性並因而選擇唯一的名稱,來保證這些庫可以被同時使用.通常用唯一的字符串加前綴的方法來解決,如數據庫類被冠以My_Library_DB,等等.當這個庫增加的時候,前綴也隨著增加,這樣導致很長的名字.命名空間使開發者在每次引用類的時候不使用長名稱即可管理命名范
圍.
定義
命名空間在每一個文件的開頭以namespace 關鍵字來聲明,如
<?php
namespace MyProject::DB;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
相同的namespace 名稱可以在多個文件中使用
namespace 包class,constant和function定義,但無free code
詳解:
在命名空間內部,所有定義的class,function和constant名稱被自動冠以命名空間名稱,類名總是完整的名稱,如,以上例子中的類使用MyProject::DB::Connection
來調用
創建的常量,名稱是由命名空間名加上常量名,象類常量、命名空間常量只能為靜態常量。
非完整修飾名(如名稱不包含::),遵循如下:
非自動加載類在當前命名空間(冠以命名空間名稱的)中查找
非自動加載全局命名空間中查找
Autoloading for name in current namespace is attempted.
如前者查找失敗,則查找失敗
非完整修飾函數名稱(如名稱不包含::)先在當前命名空間查找再在全局空間中查找
非完整修飾常量名稱稱在當前命名空間中查找再在全局定義的常量裡查找
使用命名空間
每一個命名空間裡的類和函數可使用全名來引用,如,MyProject::DB::Connection ,或MyProject::DB::Connection
<?php
require 'MyProject/Db/Connection.php';
$x = new MyProject::DB::Connection;
MyProject::DB::connect();
?>
命名空間可以使用use操作符來引入到當前上下文(全局或命名空間)中,這個操作符參數如下:
<?php
/* ... */
use Some::Name as Othername;
// 簡化應用
use Foo::Bar;
// 與其相同
use Foo::Bar as Bar;
?>
引入的名稱工作如下:每次當解釋器遇到局部名稱Othername(單一名稱或被::分隔的長名稱),引入的名稱Some::Name被替代
use只能用於全局范圍內,非函數或類中,引入的名稱從引入開始到當前文件結尾有效,推薦在文件最開始引入以避免沖突
<?php
require 'MyProject/Db/Connection.php';
use MyProject::DB;
use MyProject::DB::Connection as DbConnection;
$x = new MyProject::DB::Connection();
$y = new DB::connection();
$z = new DbConnection();
DB::connect();
?>
全局空間
沒有命名空間定義時,所有的類和函數都被放在全局空間內,因為在PHP支持命名空間前就是這樣的.
在命名空間上下文中,被冠以::將指定來自全局空間裡該名稱
<?php
namespace A::B::C;
/* 此函數為 A::B::C::fopen */
function fopen() {
/* ... */
$f = ::fopen(...); // 全局函數
return $f;
}
?>
__NAMESPACE__
解釋期間的常量__NAMESPACE__被定義為當前命名空間的名稱,在命名空間外部,這個常量值為空字符串.
<?php
namespace A::B::C;
function foo() {
// do stuff
}
set_error_handler(__NAMESPACE__ . "::foo");
?>
規則
1.所有完整修飾名通過當前引入規則轉化,如A::B::C已引入,C::D::E()被轉化為A::B::C::D::e().
2.非完整修飾名通過當前引入規則轉化(全名替換簡名),如A::B::C已引入,new C()被轉化為A::B::C().
3.在命名空間內部,調用當前命名空間內定義的非完整修飾函數名,在解釋期間被認為是調用這些命名空間的函數
4.在命名空間內部(A::B),調用在當前命名空間內沒有定義的非完整修飾名函數在運行期間被決定,以下是Foo()如何被決定
在當前命名空間內尋找函數A::B::foo().
嘗試尋找和調用內部(internal)函數foo()
調用全局空間內用戶定義的函數,使用::foo()
5.在命名空間內部(A::B),調用在當前命名空間內沒有定義的非完整修飾名類在運行期間被決定,以下是 new C() 如何被決定.
在當前命名空間A::B::C中尋找類
嘗試尋找和調用內部類C
嘗試自動加載A::B::C
調用全局空間內用戶自定義的類,使用new ::c()
6.調用完整修飾名的函數在運行期間被決定.以下是A::B::foo() 如何被決定
在當前命名空間內尋找函數A::B::foo().
調用全局空間內用戶定義的函數,使用::foo()
7.調用完整修飾名的類的時候,是在運行的時候才按照想對應的命名空間來加載。比如 new A::B::C() 它是引用 命名空間是A::B下的C() 類
<?php
namespace A;
// 函數調用
foo(); // 先嘗試調用命名空間A裡定義的"foo
// 再調用內部(internal)函數 "foo"
::foo(); // 調用全局范圍內定義的"foo"
// 類引用
new B(); // 先嘗試創建在命名空間A定義的B類的對象
// 再創建內部類B對象
new ::B(); //新建全局域定義的B類的對象
// 來自其他命名空間的靜態方法/命名空間
B::foo(); //先嘗試調用來自命名空間"A::B"的函數foo()
// 再調用內部類B的函數foo()
::B::foo(); //先嘗試調用來自命名空間B的函數FOO()
//再調用全局域裡B裡的函數FOO()
//當前命名空間的靜態方法/命名空間
A::foo(); //先調用命名空間"A::A" 裡的函數FOO()
// 再調用命名空間A裡A類的函數foo()
// 再嘗試調用命名空間A裡函數foo()
// 再調用內部類A裡的函數foo()
::A::foo(); // 先嘗試調用命名空間A裡函數foo()
// 再調用全局域裡A類的函數foo()
?>