名前解決のルール
(PHP 5 >= 5.3.0, PHP 7, PHP 8)
名前解決のルールを説明するにあたって、いくつかの重要な定義を示しておきます。
- 非修飾名
- これは名前空間区切り文字を含まない識別子で、
Foo
のようなものです。 - 修飾名
- これは名前空間区切り文字を含む識別子で、
Foo\Bar
のようなものです。 - 完全修飾名
- これは名前空間区切り文字を含む識別子のうち先頭が名前空間区切り文字で始まるもので、
\Foo\Bar
のようなものです。名前空間\Foo
も完全修飾名です。 - 相対名
namespace\Foo\Bar
のように、namespace
で始まる識別子です。
名前解決は、これらの解決ルールによって行われます。
- 完全修飾名は、先頭の名前空間区切り文字を除いた名前に常に解決されます。 たとえば、
\A\B
はA\B
と解釈されます。 - 相対名は、
namespace
という名前を、 現在の名前空間に置き換えたものに常に解決されます。 現在の名前空間がグローバル名前空間だった場合、namespace\
名前空間は取り除かれます。 たとえば、名前空間X\Y
の中にあるnamespace\A
は、X\Y\A
に解決されます。 グローバル名前空間の中にある同じ名前は、A
に解決されます。 - 修飾名の場合は、名前の最初の識別子を、 現在のクラス/名前空間のインポートテーブルに従って翻訳します。 たとえば、名前空間
A\B\C
がC
としてインポートされた場合、C\D\E
という名前は、A\B\C\D\E
と翻訳されます。 - 修飾名の場合で、適用すべきインポートルールがない場合、 現在の名前空間が名前の先頭に付加されます。 たとえば、名前空間
A\B
の中にあるC\D\E
という名前はA\B\C\D\E
に解決されます。 - 非修飾名の場合、名前はそれぞれのシンボルタイプの 現在のインポートテーブルに従って翻訳されます。 これは、クラスのような名前は、クラス/名前空間のインポートテーブルに従って 翻訳されるし、関数名は、関数のインポートテーブルに従うし、 定数は定数のインポートテーブルに従うということになります。 たとえば、
use A\B\C;
の後に、new C()
のようなことをすると、 C はA\B\C()
に解決されます。 同じように、use function A\B\fn;
の後にfn()
のようなことをすると、A\B\fn
という名前に解決されます。 - 非修飾名について、適用すべきインポートルールが存在せず、 名前がクラスのようなシンボルを参照している場合、 現在の名前空間が先頭に付加されます。 たとえば、名前空間
A\B
の内部にあるnew C()
は、A\B\C
という名前に解決されます。 - 非修飾名について、適用すべきインポートルールが存在せず、 名前が関数や定数を参照しており、 コードがグローバル名前空間の外に存在する場合は 名前は実行時に解決されます。 コードが名前空間
A\B
の中にあると仮定すると、 関数foo()
のコールは、次のように解決されます。- まず現在の名前空間から関数
A\B\foo()
を探します。 - 次に グローバル 関数
foo()
を探します。
- まず現在の名前空間から関数
例1 名前解決の例
<?phpnamespace A;use B\D, C\E as F;// 関数のコールfoo(); // まず名前空間 "A" で定義されている "foo" のコールを試み、 // 次にグローバル関数 "foo" をコールします\foo(); // グローバルスコープで定義されている関数 "foo" をコールしますmy\foo(); // 名前空間 "A\my" で定義されている関数 "foo" をコールしますF(); // まず名前空間 "A" で定義されている "F" のコールを試み、 // 次にグローバル関数 "F" をコールします// クラスの参照new B(); // 名前空間 "A" で定義されているクラス "B" のオブジェクトを作成します // 見つからない場合は、クラス "A\B" の autoload を試みますnew D(); // インポートルールを使用し、名前空間 "B" で定義されているクラス "D" のオブジェクトを作成します // 見つからない場合は、クラス "B\D" の autoload を試みますnew F(); // インポートルールを使用し、名前空間 "C" で定義されているクラス "E" のオブジェクトを作成します // 見つからない場合は、クラス "C\E" の autoload を試みますnew \B(); // グローバルスコープで定義されているクラス "B" のオブジェクトを作成します // 見つからない場合は、クラス "B" の autoload を試みますnew \D(); // グローバルスコープで定義されているクラス "D" のオブジェクトを作成します // 見つからない場合は、クラス "D" の autoload を試みますnew \F(); // グローバルスコープで定義されているクラス "F" のオブジェクトを作成します // 見つからない場合は、クラス "F" の autoload を試みます// 別の名前空間から使用する静的メソッド/関数B\foo(); // 名前空間 "A\B" の関数 "foo" をコールしますB::foo(); // 名前空間 "A" で定義されているクラス "B" のメソッド "foo" をコールします // クラス "A\B" が見つからない場合はクラス "A\B" の autoload を試みますD::foo(); // インポートルールを使用し、名前空間 "B" で定義されているクラス "D" のメソッド "foo" をコールします // クラス "B\D" が見つからない場合はクラス "B\D" の autoload を試みます\B\foo(); // 名前空間 "B" の関数 "foo" をコールします\B::foo(); // グローバルスコープのクラス "B" のメソッド "foo" をコールします // クラス "B" が見つからない場合はクラス "B" の autoload を試みます// 現在の名前空間から使用する静的メソッド/関数A\B::foo(); // 名前空間 "A\A" のクラス "B" のメソッド "foo" をコールします // クラス "A\A\B" が見つからない場合はクラス "A\A\B" の autoload を試みます\A\B::foo(); // 名前空間 "A" のクラス "B" のメソッド "foo" をコールします // クラス "A\B" が見つからない場合はクラス "A\B" の autoload を試みます?>