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

(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
Автор:
It took me playing with it a bit  as I had a hard time finding documentation on when a class name matches a namespace, if that's even legal and what behavior to expect.  It IS explained in #6 but I thought I'd share this with other souls like me that see it better by example.  Assume all 3 files below are in the same directory.

file1.php
<?php
namespace foo;

class 
foo {
  static function 
hello() {
    echo 
"hello world!";
  }
}
?>

file2.php
<?php
namespace foo
include(
'file1.php');

foo::hello(); //you're in the same namespace, or scope.
\foo\foo::hello(); //called on a global scope.
?>

file3.php
<?php
include('file1.php');

foo\foo::hello(); //you're outside of the namespace
\foo\foo::hello(); //called on a global scope.
?>

Depending upon what you're building (example: a module, plugin, or package on a larger application), sometimes declaring a class that matches a namespace makes sense or may even be required.  Just be aware that if you try to reference any class that shares the same namespace, omit the namespace unless you do it globally like the examples above.

I hope this is useful, particularly for those that are trying to wrap your head around this 5.3 feature.
2014-02-14 23:52:00
http://php5.kiev.ua/manual/ru/language.namespaces.rules.html
Can someone explain to me -  why do we need p.4 if we have p.2 (which covers both unqualified and qualified names)?
2014-07-11 13:02:02
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

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