最近更新: 2009-11-24

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 就萬事大吉,但至少在結合來自各路好漢的函數庫與功能框架時,不必太擔心名稱衝突的問題了。

相關文章
樂多舊網址: http://blog.roodo.com/rocksaying/archives/10814499.html

樂多舊回應
cedriccefc2002@gmail.com(泰迪熊的私藏蜂蜜) (#comment-21669751)
Fri, 18 Mar 2011 00:26:09 +0800
受了你文章的啟發,我寫了一個可以混成PHP命名空間的類別在:http://cedric0206.blogspot.com/2011/03/php-namespace-mix-in.html
sheephead0818@hotmail.com(Ryan.Yang) (#comment-22804268)
Mon, 11 Mar 2013 14:23:05 +0800
你文章寫得真好阿~完全有看有懂,也詳細
看到發文日不由得笑了一下...
ty anyway