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().

Example #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"
?>