The term "autoload" mentioned here shall not be confused with __autoload function to autoload objects. Regarding the __autoload and namespaces' resolution I'd like to share the following experience:
->Say you have the following directory structure:
- root
| - loader.php
| - ns
| - foo.php
->foo.php
<?php
namespace ns;
class foo
{
public $say;
public function __construct()
{
$this->say = "bar";
}
}
?>
-> loader.php
<?php
//GLOBAL SPACE <--
function __autoload($c)
{
require_once $c . ".php";
}
class foo extends nsfoo // ns\foo is loaded here
{
public function __construct()
{
parent::__construct();
echo "<br />foo" . $this->say;
}
}
$a = new nsfoo(); // ns\foo also loads ns/foo.php just fine here.
echo $a->say; // prints bar as expected.
$b = new foo; // prints foobar just fine.
?>
If you keep your directory/file matching namespace/class consistence the object __autoload works fine.
But... if you try to give loader.php a namespace you'll obviously get fatal errors.
My sample is just 1 level dir, but I've tested with a very complex and deeper structure. Hope anybody finds this useful.
Cheers!
名前解決のルール
名前解決のルールを説明するにあたって、いくつかの重要な定義を示しておきます。
-
名前空間名の定義
- 非修飾名
-
これは名前空間区切り文字を含まない識別子で、Foo のようなものです。
- 修飾名
-
これは名前空間区切り文字を含む識別子で、Foo\Bar のようなものです。
- 完全修飾名
-
これは名前空間区切り文字を含む識別子のうち先頭が名前空間区切り文字で始まるもので、 \Foo\Bar のようなものです。namespace\Foo も完全修飾名です。
名前解決は、これらの解決ルールによって行われます。
- 完全修飾された関数、クラス、定数へのコールはコンパイル時に解決されます。 たとえば、new \A\B は A\B クラスと解釈されます。
- 非修飾名および (完全修飾でない) 修飾名の変換は、現在のインポートルールに基づいてコンパイル時に行われます。 たとえば、名前空間 A\B\C が C という名前でインポートされている場合、 C\D\e() へのコールは A\B\C\D\e() と変換されます。
- 名前空間内で、インポートルールによる変換が行われなかった修飾名は 現在の名前区間が先頭に付加されます。たとえば、 C\D\e() へのコールが名前空間 A\B 内で行われた場合、それは A\B\C\D\e() に変換されます。
- 非修飾クラス名の変換は、現在のインポートルールに基づいてコンパイル時に行われます (フルネームが、インポートされた短い名前に置き換えられます)。たとえば、 名前空間 A\B\C が C という名前でインポートされている場合、 new C() は new A\B\C() と変換されます。
-
名前空間内 (ここでは A\B としましょう) で、非修飾な関数へのコールは実行時に解決されます。
関数 foo() のコールは、次のように解決されます。
- まず現在の名前空間から関数 A\B\foo() を探します。
- 次に グローバル 関数 foo() を探します。
-
名前空間内 (ここでは A\B としましょう) で、
非修飾あるいは (完全修飾でない) 修飾なクラスへのコールは実行時に解決されます。
new C() や new D\E()
がどのように解決されるかを示します。
new C() の場合は、
- まず現在の名前空間からクラス A\B\C を探します。
- A\B\C を autoload します。
- 現在の名前空間を先頭につけた A\B\D\E を探します。
- A\B\D\E を autoload します。
例1 名前解決の例
<?php
namespace 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" のクラス "B" のメソッド "foo" をコールします
// クラス "A\B" が見つからない場合はクラス "A\B" の autoload を試みます
?>
名前解決のルール
rangel
31-Jul-2009 07:48
31-Jul-2009 07:48
rangel
31-Jul-2009 07:47
31-Jul-2009 07:47
The term "autoload" mentioned here shall not be confused with __autoload function to autoload objects. Regarding the __autoload and namespaces' resolution I'd like to share the following experience:
->Say you have the following directory structure:
- root
| - loader.php
| - ns
| - foo.php
->foo.php
<?php
namespace ns;
class foo
{
public $say;
public function __construct()
{
$this->say = "bar";
}
}
?>
-> loader.php
<?php
//GLOBAL SPACE <--
function __autoload($c)
{
require_once $c . ".php";
}
class foo extends nsfoo // ns\foo is loaded here
{
public function __construct()
{
parent::__construct();
echo "<br />foo" . $this->say;
}
}
$a = new nsfoo(); // ns\foo also loads ns/foo.php just fine here.
echo $a->say; // prints bar as expected.
$b = new foo; // prints foobar just fine.
?>
If you keep your directory/file matching namespace/class consistence the object __autoload works fine.
But... if you try to give loader.php a namespace you'll obviously get fatal errors.
My sample is just 1 level dir, but I've tested with a very complex and deeper structure. Hope anybody finds this useful.
Cheers!
