Правила разрешения имен

(PHP 5 >= 5.3.0, PHP 7)

Для этих правил здесь приведены несколько важных определений:

Определения имени пространства имен
Неполное имя

Это идентификатор без разделителя пространств имен, например, Foo

Полное имя

Это идентификатор с разделителем пространств имен, например, Foo\Bar

Абсолютное имя

Это идентификатор с разделителем пространств имен, который начинается с разделителя пространств имен, например, \Foo\Bar. Пространство имен \Foo также является абсолютным именем.

Имена разрешаются согласно следующим правилам:

  1. Вызовы абсолютных функций, классов или констант разрешаются во время компиляции. Например, new \A\B разрешается в класс A\B.
  2. Все неполные и полные имена (не абсолютные) переводятся в процессе компиляции в соответствии с текущими правилами импорта. Например, если пространство имен A\B\C импортировано как C, вызов 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. PHP пытается найти и вызвать функцию глобального пространства foo().
  6. Внутри пространства имен (скажем, A\B), вызовы к неполным или полным именам классов (неабсолютным) преобразуются во время исполнения. Вот как выражение new C() или new D\E() преобразуется. Для new C():
    1. Ищется класс из текущего пространства имен: A\B\C.
    2. Производится попытка автозагрузки A\B\C.
    Для new D\E():
    1. Ищется класс с помощью префиксации текущего пространства имен: A\B\D\E.
    2. Производится попытка автозагрузки A\B\D\E.
    Для обращения к любому глобальному классу в глобальном пространстве, должно использоваться его абсолютное имя new \C().

Пример #1 Примеры разрешения имен

<?php
namespace A;
use 
B\DC\as F;

// вызовы функций

foo();      // сперва пытается вызвать "foo", определенную в пространстве имен "A",
            // затем вызывает глобальную функцию "foo"

\foo();     // вызывает функцию "foo", определенную в глобальном пространстве

my\foo();   // вызывает функцию "foo", определенную в пространстве "A\my"

F();        // сперва пытается вызвать "F", определенную в пространстве имен "A",
            // затем вызывает глобальную функцию "F"

// ссылки на классы

new B();    // создает объект класса "B", определенного в пространстве имен "A".
            // если не найден, то пытается сделать автозагрузку класса "A\B"

new D();    // используя правила импорта, создает объект класса "D", определенного в пространстве имен "B"
            // если не найден, то пытается сделать автозагрузку класса "B\D"

new F();    // используя правила импорта, создает объект класса "E", определенного в пространстве имен "C"
            // если не найден, то пытается сделать автозагрузку класса "C\E"

new \B();   // создает объект класса "B", определенного в глобальном пространстве,
            // если не найден, то пытается сделать автозагрузку класса "B"

new \D();   // создает объект класса "D", определенного в глобальном пространстве,
            // если не найден, то пытается сделать автозагрузку класса "D"

new \F();   // создает объект класса "F", определенного в глобальном пространстве,
            // если не найден, то пытается сделать автозагрузку класса "F"

// статические методы/функции пространства имен из другого пространства имен

B\foo();    // вызывает функцию "foo" из пространства имен "A\B"

B::foo();   // вызывает метод "foo" из класса "B", определенного в пространстве имен "A"
            // если класс "A\B" не найден, то пытается сделать автозагрузку класса "A\B"

D::foo();   // используя правила импорта, вызывает метод "foo" класса "D", определенного в пространстве имен "B"
            // если класс "B\D" не найден, то пытается сделать автозагрузку класса "B\D"

\B\foo();   // вызывает функцию "foo" из пространства имен "B"

\B::foo();  // вызывает метод "foo" класса "B" из глобального пространства
            // если класс "B" не найден, то пытается сделать автозагрузку класса "B"

// статические методы/функции пространства имен из текущего пространства имен

A\B::foo();   // вызывает метод "foo" класса "B" из пространства имен "A\A"
              // если класс "A\A\B" не найден, то пытается сделать автозагрузку класса "A\A\B"

\A\B::foo();  // вызывает метод "foo" класса "B" из пространства имен "A"
              // если класс "A\B" не найден, то пытается сделать автозагрузку класса "A\B"
?>

Коментарии

Автор:
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 ns\foo // ns\foo is loaded here
{
    public function 
__construct()
    {
       
parent::__construct();
        echo 
"<br />foo" $this->say;
    }
}
$a = new ns\foo(); // 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!
2009-07-31 03:47:51
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html
Автор:
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 ns\foo // ns\foo is loaded here
{
    public function 
__construct()
    {
       
parent::__construct();
        echo 
"<br />foo" $this->say;
    }
}
$a = new ns\foo(); // 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!
2009-07-31 03:48:15
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html
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)
    {
       
\Glue\Import::load($classname);
    }

}
?>
2010-10-22 04:04:19
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html
Автор:
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.
2010-10-27 21:35:20
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html
Автор:
For point 4, "In example, if the namespace A\B\C is imported as C" should be "In example, if the class A\B\C is imported as C".
2014-01-22 12:25:03
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html
Автор:
The mentioned filesystem analogy fails at an important point:

Namespace resolution *only* works at declaration time. The compiler fixates all namespace/class references as absolute paths, like creating absolute symlinks.

You can't expect relative symlinks, which should be evaluated during access -> during PHP runtime.

In other words, namespaces are evaluated like __CLASS__ or self:: at parse-time. What's *not* happening, is the pendant for late static binding like static:: which resolves to the current class at runtime.

So you can't do the following:

namespace Alpha;
class Helper {
    public static $Value = "ALPHA";
}
class Base {
    public static function Write() { 
        echo Helper::$Value;
    }
}

namespace Beta;
class Helper extends \Alpha\Helper {
    public static $Value = 'BETA';
}   
class Base extends \Alpha\Base {}   

\Beta\Base::Write(); // should write "BETA" as this is the executing namespace context at runtime.

If you copy the write() function into \Beta\Base it works as expected.
2014-12-21 15:05:40
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html
Namespaces may be case-insensitive, but autoloaders most often do.
Do yourself a service, keep your cases consistent with file names, and don't overcomplicate autoloaders beyond necessity.
Something like this should suffice for most times:

<?php

namespace org\example;

function 
spl_autoload($className)
{
 
$file = new \SplFileInfo(__DIR__ substr(strtr("$className.php"'\\''/'), 11));
 
$path $file->getRealPath();
  if(empty(
$path))
  {
    return 
false;
  }
  else
  {
    return include_once 
$path;
  }
}

\spl_autoload_register('\org\example\spl_autoload');
?>
2016-02-13 00:32:45
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html

    Поддержать сайт на родительском проекте КГБ