名稱解析規(guī)則

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

在說明名稱解析規(guī)則之前,我們先看一些重要的定義:

命名空間名稱定義
非限定名稱(Unqualified name)

名稱中不包含命名空間分隔符的標(biāo)識(shí)符,例如 Foo

限定名稱(Qualified name)

名稱中含有命名空間分隔符的標(biāo)識(shí)符,例如 Foo\Bar

完全限定名稱(Fully qualified name)

名稱中包含命名空間分隔符,并以命名空間分隔符開始的標(biāo)識(shí)符,例如 \Foo\Bar。 namespace\Foo 也是一個(gè)完全限定名稱。

相對(duì)名稱(Relative name)

這是個(gè)以 namespace 開頭的標(biāo)識(shí)符, 例如 namespace\Foo\Bar。

名稱解析遵循下列規(guī)則:

  1. 完全限定名稱總是會(huì)解析成沒有前綴符號(hào)的命名空間名稱。 \A\B 解析為 A\B。
  2. 解析相對(duì)名稱時(shí),會(huì)用當(dāng)前命名空間的名稱替換掉 namespace。 如果名稱出現(xiàn)在全局命名空間,會(huì)截掉 namespace\ 前綴。 例如,在命名空間 X\Y 里的 namespace\A 會(huì)被解析成 X\Y\A。 在全局命名空間里,同樣的名字卻被解析成 A。
  3. 對(duì)于限定名稱,名字的第一段會(huì)根據(jù)當(dāng)前 class/namespace 導(dǎo)入表進(jìn)行翻譯。 比如命名空間 A\B\C 被導(dǎo)入為 C, 名稱 C\D\E 會(huì)被翻譯成 A\B\C\D\E。
  4. 對(duì)于限定名稱,如果沒有應(yīng)用導(dǎo)入規(guī)則,就將當(dāng)前命名空間添加為名稱的前綴。 例如,位于命名空間 A\B 內(nèi)的名稱 C\D\E 會(huì)解析成 A\B\C\D\E。
  5. 根據(jù)符號(hào)類型和對(duì)應(yīng)的當(dāng)前導(dǎo)入表,解析非限定名稱。 這也就是說,根據(jù) class/namespace 導(dǎo)入表翻譯類名稱; 根據(jù)函數(shù)導(dǎo)入表翻譯函數(shù)名稱; 根據(jù)常量導(dǎo)入表翻譯常量名稱。 比如,在 use A\B\C; 后,類似 new C() 這樣的名稱會(huì)解析為 A\B\C()。 類似的,use function A\B\fn; 后, fn() 的用法,解析名稱為 A\B\fn
  6. 如果沒有應(yīng)用導(dǎo)入規(guī)則,對(duì)于類似 class 符號(hào)的非限定名稱,會(huì)添加當(dāng)前命名空間作為前綴。 比如命名空間 A\B 內(nèi)的 new C() 會(huì)把名稱解析為 A\B\C。
  7. 如果沒有應(yīng)用導(dǎo)入規(guī)則,非限定名稱指向函數(shù)或常量,且代碼位于全局命名空間之外,則會(huì)在運(yùn)行時(shí)解析名稱。 假設(shè)代碼位于命名空間 A\B 中, 下面演示了調(diào)用函數(shù) foo() 是如何解析的:
    1. 在當(dāng)前命名空間中查找函數(shù): A\B\foo()
    2. 它會(huì)嘗試找到并調(diào)用 全局 的函數(shù) foo()。

示例 #1 名稱解析示例

<?php
namespace A;
use 
B\DC\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" 的一個(gè)對(duì)象
            // 如果未找到,則嘗試自動(dòng)裝載類 "A\B"

new D();    // 使用導(dǎo)入規(guī)則,創(chuàng)建命名空間 "B" 中定義的類 "D" 的一個(gè)對(duì)象
            // 如果未找到,則嘗試自動(dòng)裝載類 "B\D"

new F();    // 使用導(dǎo)入規(guī)則,創(chuàng)建命名空間 "C" 中定義的類 "E" 的一個(gè)對(duì)象
            // 如果未找到,則嘗試自動(dòng)裝載類 "C\E"

new \B();   // 創(chuàng)建定義在全局空間中的類 "B" 的一個(gè)對(duì)象
            // 如果未發(fā)現(xiàn),則嘗試自動(dòng)裝載類 "B"

new \D();   // 創(chuàng)建定義在全局空間中的類 "D" 的一個(gè)對(duì)象
            // 如果未發(fā)現(xiàn),則嘗試自動(dòng)裝載類 "D"

new \F();   // 創(chuàng)建定義在全局空間中的類 "F" 的一個(gè)對(duì)象
            // 如果未發(fā)現(xiàn),則嘗試自動(dòng)裝載類 "F"

// 調(diào)用另一個(gè)命名空間中的靜態(tài)方法或命名空間函數(shù)

B\foo();    // 調(diào)用命名空間 "A\B" 中函數(shù) "foo"

B::foo();   // 調(diào)用命名空間 "A" 中定義的類 "B" 的 "foo" 方法
            // 如果未找到類 "A\B" ,則嘗試自動(dòng)裝載類 "A\B"

D::foo();   // 使用導(dǎo)入規(guī)則,調(diào)用命名空間 "B" 中定義的類 "D" 的 "foo" 方法
            // 如果類 "B\D" 未找到,則嘗試自動(dòng)裝載類 "B\D"

\B\foo();   // 調(diào)用命名空間 "B" 中的函數(shù) "foo" 

\B::foo();  // 調(diào)用全局空間中的類 "B" 的 "foo" 方法
            // 如果類 "B" 未找到,則嘗試自動(dòng)裝載類 "B"

// 當(dāng)前命名空間中的靜態(tài)方法或函數(shù)

A\B::foo();   // 調(diào)用命名空間 "A\A" 中定義的類 "B" 的 "foo" 方法
              // 如果類 "A\A\B" 未找到,則嘗試自動(dòng)裝載類 "A\A\B"

\A\B::foo();  // 調(diào)用命名空間 "A\B" 中定義的類 "B" 的 "foo" 方法
              // 如果類 "A\B" 未找到,則嘗試自動(dòng)裝載類 "A\B"
?>