PHP 5.3/6 新增功能 - Namespace
Namespace 是 PHP5.3 面向大型專案開發所新增的一項重要功能。並不是說有了 Namespace 就萬事大吉,但至少在結合來自各路好漢的函數庫與功能框架時,不必太擔心名稱衝突的問題了。
PHP 以 namespace 關鍵字指示名稱空間,此指令兼具定義與切換空間的意義。名稱空間的命令方式與一般符號相同,並以 \
(斜線) 作為名稱空間(namespace)的分節符號。它借用檔案系統的目錄樹觀念劃分常數(const)、函數(function)與類別(class)等定義的存在空間 (注意,名稱空間並不支援變數。所有的變數都存在於同一個空間)。
所以我們在使用常數、函數與類別內容時,可以使用絕對路徑或相對路徑指示內容所在空間。我們以限定名稱(Qualified name)稱呼包含名稱空間的符號名。以絕對路徑表示的限定名稱又稱為完整限定名稱(Fully qualified name)。而單一的 \
路徑,就表示 global namespace (全體共用名稱空間)。
<?php
namespace blog\rock; //名稱空間 blog\rock
const FOO = 1;
namespace blog; //名稱空間 blog, 位於前面名稱空間的上一層。
rock\FOO; // 以相對路徑表示的限定名稱(qualified name).
\blog\rock\FOO // 絕對路徑表示,完整限定名稱(fully qualifid name).
?>
如果你要使用名稱空間,那麼除了 declare
指令以外,namespace
指令必須是這個 PHP 文件的第一個 PHP 敘述。至於空行、註解則不是PHP敘述。
Simple combination syntax
PHP 提供了兩種名稱空間的使用語法,下例所示為簡單結合語法(simple combination)syntax)。
此例中有三個不同的 strlen()
,它們分別位於不同的名稱空間之下,即 \, \blog\rock, \blog\rock\negative
,所以視為不同的函數,不會衝突。在簡單結合語法中,當你使用 namespace
指示名稱空間之後,隨之而來的 PHP 敘述都預設使用該名稱空間,直到你再次使用 namespace 切換名稱空間。
透過預設符號 __NAMESPACE__ 可以取得目前所在的空間名稱。
<?php
//除了 declare 指令以外,namespace 指令必須是這個 PHP 文件的第一個 PHP 敘述。
//至於空行、註解則不是PHP敘述。
namespace blog;
const HELLO = 'Hello blog'; // Fully qualified name is \blog\HELLO
namespace blog\rock; //定義並切換到 blog\rock 名稱空間
const HELLO = 'Hello rock';
function strlen($s) {
return "invoke strlen() at " . __NAMESPACE__ . ', argument (' . $s . ')';
}
echo "-- access HELLO --\n";
echo strlen( HELLO ), "\n";
echo strlen( \blog\HELLO ), "\n"; //使用完整限定名稱取得 blog 空間的 HELLO 常數
namespace blog\rock\negative; //定義並切換到 blog\rock\negative 名稱空間
function strlen($s) {
//在 blog\rock\negative 空間的 strlen() 會將字串長度以負值傳回。
return -( \strlen($s) );
}
namespace blog\rock; //切換到 blog\rock 名稱空間
echo "\n";
echo "-- invoke strlen() --\n";
echo strlen( HELLO ), "\n";
echo negative\strlen( HELLO ), "\n"; //使用相對路徑
echo \blog\rock\negative\strlen( HELLO ), "\n"; //使用絕對路徑
echo \strlen( HELLO ), "\n";
?>
執行結果。
-- access HELLO -- invoke strlen() at blog\rock, argument (Hello rock) invoke strlen() at blog\rock, argument (Hello blog) -- invoke strlen() -- invoke strlen() at blog\rock, argument (Hello rock) -10 -10 10
Bracketed syntax
當你需要在同一份文件中多次切換名稱空間時, PHP 官方建議使用括弧語法(bracketed syntax)。因為配合段落縮排後,會讓你比較容易看清楚目前的 PHP 敘述處於哪個名稱空間之下。在同一份文件中,不能混用名稱空間的括弧語法與簡單結合語法。在同一份文件中,你只能用一種。
沿用簡單結合語法的範例,改成括弧語法,結果如下:
<?php
// Namespace, 括弧語法 (bracketed syntax)
namespace blog {
const HELLO = 'Hello blog'; // Fully qualified name is \blog\HELLO
}
namespace blog\rock { //定義並切換到 blog\rock 名稱空間
const HELLO = 'Hello rock';
function strlen($s) {
return "invoke strlen() at " . __NAMESPACE__ . ', argument (' . $s . ')';
}
echo "-- access HELLO --\n";
echo strlen( HELLO ), "\n";
echo strlen( \blog\HELLO ), "\n"; //使用完整限定名稱取得 blog 空間的 HELLO 常數
}
namespace blog\rock\negative { //定義並切換到 blog\rock\negative 名稱空間
function strlen($s) {
//在 blog\rock\negative 空間的 strlen() 會將字串長度以負值傳回。
return -( \strlen($s) );
}
}
namespace blog\rock { //切換到 blog\rock 名稱空間
echo "\n";
echo "-- invoke strlen() --\n";
echo strlen( HELLO ), "\n";
echo negative\strlen( HELLO ), "\n"; //使用相對路徑
echo \blog\rock\negative\strlen( HELLO ), "\n"; //使用絕對路徑
echo \strlen( HELLO ), "\n";
}
?>
當我們在同一份文件中多次切換名稱空間時,配合縮排的括弧語法較易閱讀。當然,你也可以用簡單結合語法,再引用 Pythan 撰寫習慣,直接用空格縮排來區分名稱空間。但是只有使用括弧語法,我們才能切換到全體共用名稱空間(global namespace)。
匯入與別名功能
如果我們只是想使用別的名稱空間的內容,並不想切換名稱空間,則可用 use 匯入其他空間的內容。我們同時可以指定匯入空間的別名。如果你單獨匯入其他空間的一個類別定義 (不能單獨匯入名稱空間內的函數或常數),你也可以指定那個類別的別名。
動態地存取元素
如同 Variable functions 允許我們所做的事一般,PHP 也允許我們透過變數去使用其他空間的內容。
但要注意 \
字元的跳脫處理,如果你用雙引號括起名稱空間的內容,那麼字串中的 \
要寫成 \\
。
<?php
namespace blog\rock {
function bar() {
echo "BAR\n";
}
class Ccllaass {
public static function bar() {
echo "cc\n";
}
}
}
namespace { // namespace without name means global namespace
function bar() {
echo "bar\n";
}
use \blog\rock as rock; // 匯入名稱空間並取別名為 rock
use \blog\rock\Ccllaass as Cc; // 匯入名稱空間下的類別並取別名為 Cc
$rock_bar = '\blog\rock\bar'; //動態存取空間內的元素
$cc = '\blog\rock\Ccllaass';
$clz = 'Ccllaass';
$cc2 = "\\blog\\rock\\$clz"; //注意 \ 的跳脫處理
bar();
rock\bar();
$rock_bar();
Cc::bar();
$cc::bar();
$cc2::bar();
}
?>
執行結果:
bar BAR BAR cc cc cc
Namespace 是 PHP5.3 面向大型專案開發所新增的一項重要功能。並不是說有了 Namespace 就萬事大吉,但至少在結合來自各路好漢的函數庫與功能框架時,不必太擔心名稱衝突的問題了。
樂多舊回應