摘要訊息 : 學習 PHP 中的名稱空間.

0. 前言

命名空間 (名稱空間) 是現代 PHP (Modern PHP) 中的一個非常重要的特性. 命名空間的概念在 PHP 5.3 時引入, 使 PHP 有了如今的發展. 現代的 PHP 組件與框架各放置在自己的命名空間中, 以防命名衝突.

首先我們對命名空間的名稱進行剖析 :

namespace Jonny\Blog\Plugin\Comment;

這種結構有點類似於操作系統中的檔案夾路徑. 一般, 我們習慣於將第一個命名為廠商、項目所有者或者項目的名稱. 例如上述命名空間宣告, 首先宣告了 Jonny 這個最頂層命名空間, 之後所有的命名空間都屬於 Jonny 的子命名空間. 類推的, PluginBlog 的子命名空間, CommentPlugin 的子命名空間.

假設我現在需要建立一個 PHP 項目 (namespace Jonny), 它是一個博客項目 (namespace Jonny\Blog), 包括了 :

  • 文章模塊 : namespace Jonny\Blog\Article;
  • 評論模塊 : namespace Jonny\Blog\Comment;
  • 搜尋模塊 : namespace Jonny\Blog\Search;
  • 媒體模塊 : namespace Jonny\Blog\Media;
  • 外掛模塊 : namespace Jonny\Blog\Plugin;
  • 外觀模塊 : namespace Jonny\Blog\Theme;
  • 工具模塊 : namespace Jonny\Blog\Tool.

本文於 2022 年 3 月 18 日進行一次更新和修正. 修正之後本文已經歸檔, 不再享受更新.

1. 命名空間的宣告

PHP 中採用 namespace 對命名空間進行宣告, 使用 "\" 分隔符隔離命名空間與子命名空間 : namespace NameOfNameSpace;. 如果用上述的宣告方式, 那麼接下來的名稱都將屬於這個命名空間. 同時也可以使用 :

namespace NameOfNameSpace {
    NAME_SPACE
}

進行宣告.

但是, 命名空間的宣告建議遵守一個文件一個命名空間的習慣, 不建議同一個文件中出現多個命名空間.

2. 命名空間的使用

PHP 使用 use 關鍵字來導入命名空間. 假設現在有命名空間 : namespace Jonny\Blog;, 若要使用命名空間 Jonny\Blog, 那麼可以 :

use Jonny\Blog;

這樣, 命名空間中的變數和常數可以直接使用了, 但是函式、類別和介面等都是無法使用的, 如果需要使用, 則需要這樣做 :

<?php
    namespace Jonny\Debug;
    $a = 0;
    define("CON", 10);
    function get() {
        return 1;
    }
    class Foo {
        public $var;
        protected $var2;
        private $var3;
        public function func($var, $var2, $var3) {
            $this->var = $var;
            $this->var2 = $var2;
            $this->var3 = $var3;
        }
        public function call() {
            echo $this->var." ".$this->var2." ".$this->var3;
        }
    }
<?php
    require_once "Debug.php";
    use Jonny\Blog;
    echo $a;    // 結果 : 0
    echo "\n";
    echo CON;    // 結果 : 10

當我們呼叫 get 函式或者使用 Foo 類別時, 會報錯. 修正的方案為在對應的名稱前面加上命名空間 :

<?php
    require_once "Debug.php";
    use Jonny\Blog;
    echo $a;
    echo "\n";
    echo CON;
    echo "\n";
    echo Debug\get();
    $obj = new Debug\Foo();
    $obj->func(1, 2, 3);
    $obj->call();

此時就不再提示有致命錯誤.

當然還有一種方法就是在宣告命名空間的時候, 宣告對應的名稱 :

<?php
    require_once("Debug.php");
    use Jonny\Debug;
    use Jonny\Debug\Foo;
    use function Jonny\Debug\get;
    echo $a;
    echo "\n";
    echo CON;
    echo "\n";
    echo get();
    $obj = new Foo();
    $obj->func(1, 2, 3);
    $obj->call();

最終的效果和上面是一樣的.

當要使用命名空間內的函式的時候, 可以使用 : use function NAME_SPACE\NameOfFunction;; 當要使用 const 常數的時候, 可以使用 : use const NAME_SPACE\NameOfConstVar;.

PHP 支持多重命名空間的導入 :

<?php
    use Jonny\Debug\Namespace1,
    Jonny\Debug\Namespace2;

當然, 我不建議這樣去做, 而是寫成 :

<?php
    use Jonny\Debug\Namespace1;
    use Jonny\Debug\Namespace2;