Regras de resolução de nomes

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

Para efeitos destas regras de resolução, aqui estão algumas definições importantes:

Definições de nomes de namespace
Nome não qualificado

Este é um identificador sem separador de namespace, como Foo.

Nome qualificado

Este é um identificador com separador de namespace, como Foo\Bar.

Nome totalmente qualificado

Este é um identificador com separador de namespace que começa com um separador de namespace, como \Foo\Bar. O namespace \Foo também é um nome totalmente qualificado.

Nome relativo

Este é um identificador que começa com namespace, como namespace\Foo\Bar.

Os nomes são resolvidos seguindo estas regras de resolução:

  1. Nomes totalmente qualificados sempre são resolvidos para o nome sem separador de namespace à esquerda. Por exemplo, \A\B será resolvido para A\B.
  2. Nomes relativos sempre são resolvidos para o nome com namespace substituído pelo namespace atual. Se o nome ocorrer no namespace global, o prefixo namespace\ será removido. Por exemplo, namespace\A dentro do namespace X\Y será resolvido para X\Y\A. O mesmo nome dentro do namespace global será resolvido para A.
  3. Para nomes qualificados, o primeiro segmento do nome será traduzido conforme a tabela de importação de classe/namespace atual. Por exemplo, se o namespace A\B\C for importado como C, o nome C\D\E será traduzido para A\B\C\D\E.
  4. Para nomes qualificados, se nenhuma regra de importação se aplicar, o namespace atual será prefixo ao nome. Por exemplo, o nome C\D\E dentro do namespace A\B, será resolvido para A\B\C\D\E.
  5. Para nomes não qualificados, o nome será traduzido conforme a tabela de importação atual para o respectivo tipo de símbolo. Isso significa que nomes semelhantes a classes serão traduzidos conforme a tabela de importação de classe/namespace, nomes de funções conforme a tabela de importação de funções e constantes conforme a tabela de importação de constantes. Por exemplo, após a declaração use A\B\C; um uso como new C() será resolvido para o nome A\B\C(). Da mesma forma, após a declaração use function A\B\foo; um uso como foo() será resolvido para o nome A\B\foo.
  6. Para nomes não qualificados, se nenhuma regra de importação se aplicar e o nome se referir a um símbolo de classe, o namespace atual será prefixo. Por exemplo new C() dentro do namespace A\B será resolvido para o nome A\B\C.
  7. Para nomes não qualificados, se nenhuma regra de importação se aplicar e o nome se referir a uma função ou constante e o código estiver fora do namespace global, o nome será resolvido em tempo de execução. Supondo que o código esteja no namespace A\B, é assim que uma chamada para a função foo() será resolvida:
    1. Procura pela função no namespace atual: A\B\foo().
    2. Tenta encontrar e chamar a função global foo().

Exemplo #1 Resoluções de nomes ilustradas

<?php
namespace A;
use
B\D, C\E as F;

// chamadas de funções

foo(); // primeiro tenta chamar "foo" definida no namespace "A"
// então chama a função global "foo"

\foo(); // chama a função "foo" definida no escopo global

minha\foo(); // chama a função "foo" definida no namespace "A\minha"

F(); // primeiro tenta chamar "F" definida no namespace "A"
// e então chama a função global "F"

// referências de classe

new B(); // cria um objeto da classe "B" definida no namespace "A"
// se não for encontrada, tenta carregar automaticamente a classe "A\B"

new D(); // usando regras de importação, cria um objeto da classe "D" definida no namespace "B"
// se não for encontrada, tenta carregar automaticamente a classe "B\D"

new F(); // usando regras de importação, cria um objeto da classe "E" definida no namespace "C"
// se não for encontrada, tenta carregar automaticamente a classe "C\E"

new \B(); // cria um objeto da classe "B" definida no escopo global
// se não for encontrada, tenta carregar automaticamente a classe "B"

new \D(); // cria um objeto da classe "D" definida no escopo global
// se não for encontrado, tenta carregar automaticamente a classe "D"

new \F(); // cria um objeto da classe "F" definida no escopo global
// se não for encontrada, tenta carregar automaticamente a classe "F"

// métodos estáticos/funções de namespace de outro namespace

B\foo(); // chama a função "foo" do namespace "A\B"

B::foo(); // chama o método "foo" da classe "B" definida no namespace "A"
// se a classe "A\B" não for encontrada, tenta carregar automaticamente a classe "A\B"

D::foo(); // usando regras de importação, chama o método "foo" da classe "D" definida no namespace "B"
// se a classe "B\D" não for encontrada, tenta carregar automaticamente a classe "B\D"

\B\foo(); // chama a função "foo" do namespace "B"

\B::foo(); // chama o método "foo" da classe "B" do escopo global
// se a classe "B" não for encontrada, tenta carregar automaticamente a classe "B"

// métodos estáticos/funções de namespace do namespace atual

A\B::foo(); // chama o método "foo" da classe "B" do namespace "A\A"
// se a classe "A\A\B" não for encontrada, tenta carregar automaticamente a class "A\A\B"

\A\B::foo(); // chama o método "foo" da classe "B" do namespace "A"
// se a classe "A\B" não for encontrada, tenta carregar automaticamente a classe "A\B"
?>
adicione uma nota

Notas Enviadas por Usuários (em inglês) 7 notes

up
37
kdimi
14 years ago
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.
up
33
rangel
16 years ago
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<?phpnamespace 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!
up
5
safakozpinar at NOSPAM dot gmail dot com
14 years ago
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.<?phpnamespace 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);    }}?>
up
0
Kavoir.com
11 years ago
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".
up
-2
llmll
10 years ago
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.
up
-5
rangel
16 years ago
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<?phpnamespace 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!
up
-5
anrdaemon at freemail dot ru
9 years ago
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:<?phpnamespace 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');?>
To Top