downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

FAQ: 名前空間について知っておくべきこと> <名前空間の使用法: グローバル関数/定数への移行
[edit] Last updated: Fri, 25 May 2012

view this page in

名前解決のルール

(PHP 5 >= 5.3.0)

名前解決のルールを説明するにあたって、いくつかの重要な定義を示しておきます。

名前空間名の定義
非修飾名

これは名前空間区切り文字を含まない識別子で、Foo のようなものです。

修飾名

これは名前空間区切り文字を含む識別子で、Foo\Bar のようなものです。

完全修飾名

これは名前空間区切り文字を含む識別子のうち先頭が名前空間区切り文字で始まるもので、 \Foo\Bar のようなものです。namespace\Foo も完全修飾名です。

名前解決は、これらの解決ルールによって行われます。

  1. 完全修飾された関数、クラス、定数へのコールはコンパイル時に解決されます。 たとえば、new \A\BA\B クラスと解釈されます。
  2. 非修飾名および (完全修飾でない) 修飾名の変換は、現在のインポートルールに基づいてコンパイル時に行われます。 たとえば、名前空間 A\B\CC という名前でインポートされている場合、 C\D\e() へのコールは A\B\C\D\e() と変換されます。
  3. 名前空間内で、インポートルールによる変換が行われなかった修飾名は 現在の名前空間が先頭に付加されます。たとえば、 C\D\e() へのコールが名前空間 A\B 内で行われた場合、それは A\B\C\D\e() に変換されます。
  4. 非修飾クラス名の変換は、現在のインポートルールに基づいてコンパイル時に行われます (インポートされた短い名前がフルネームに置き換わります)。たとえば、 名前空間 A\B\C が C という名前でインポートされている場合、 new C()new A\B\C() と変換されます。
  5. 名前空間内 (ここでは A\B としましょう) で、非修飾な関数へのコールは実行時に解決されます。 関数 foo() のコールは、次のように解決されます。
    1. まず現在の名前空間から関数 A\B\foo() を探します。
    2. 次に グローバル 関数 foo() を探します。
  6. 名前空間内 (ここでは A\B としましょう) で、 非修飾あるいは (完全修飾でない) 修飾なクラスへのコールは実行時に解決されます。 new C()new D\E() がどのように解決されるかを示します。 new C() の場合は、
    1. まず現在の名前空間からクラス A\B\C を探します。
    2. A\B\C を autoload します。
    new D\E() の場合は、
    1. 現在の名前空間を先頭につけた A\B\D\E を探します。
    2. A\B\D\E を autoload します。
    グローバル名前空間内のグローバルクラスを参照するには、完全修飾形式の new \C() を使わなければなりません。

例1 名前解決の例

<?php
namespace A;
use 
B\DC\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 を試みます
?>


add a note add a note User Contributed Notes 名前解決のルール
kdimi 27-Oct-2010 06:35
If you like to declare an __autoload function within a namespace or class, use the spl_autoload_register() function to register it and it will work fine.
safakozpinar at NOSPAM dot gmail dot com 22-Oct-2010 01:04
As working with namespaces and using (custom or basic) autoload structure; magic function __autoload must be defined in global scope, not in a namespace, also not in another function or method.

<?php
namespace Glue
{
   
/**
     * Define your custom structure and algorithms
     * for autoloading in this class.
     */
   
class Import
   
{
        public static function
load ($classname)
        {
            echo
'Autoloading class '.$classname."\n";
            require_once
$classname.'.php';
        }
    }
}

/**
 * Define function __autoload in global namespace.
 */
namespace {
   
    function
__autoload ($classname)
    {
       
GlueImport::load($classname);
    }

}
?>
sammaye 12-Jun-2010 04:24
I have noticed one problem with __autoload function. Say you have two namespaces, one is a sub of the other:

\Glue
\Glue\Import

Within that Import namespace you have a function auto() with the magic __autoload inside. No matter what you do that auto() will never traverse it's sub function meaning you will nevber get an __autoload function.

Even if you put the __autoload within a class within the namespace as such:

<?php
namespace GlueImport
;

class
import{
    private static
$_AutoLoad = array();
    private static
$_Imported = array();

    function
load($sName){
        if(! isset(
self::$_AutoLoad[$sName]))
           
//throw new ImportError("Cannot import module with name '$sName'.");
           
echo("file with name '$sName' failed to load with path '".self::$_AutoLoad[$sName]."'");
        if(! isset(
self::$_Imported[$sName])){
           
self::$_Imported[$sName] = True;
            return include_once(
self::$_AutoLoad[$sName]);       
        }
    }
   
    function
push($sName, $sPath){
       
self::$_AutoLoad[$sName] = $sPath;
    }
   
    function
auto(){
        function
__autoload($sClass){
           
load($sClass);
        }
    }
}
?>

It will not work. Just something to keep in mind.
rangel 31-Jul-2009 12:48
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!
rangel 31-Jul-2009 12: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!

 
show source | credits | sitemap | contact | advertising | mirror sites