NamespacesVisão geral de NamespacesVisão Geral
O que são namespaces? Na definição mais ampla, os namespaces (na tradução literal, "espaços de nomes") são uma forma de encapsular
itens. Isso é visto como um conceito abstrato em muitos lugares. Por exemplo, em qualquer
sistema operacional, os diretórios servem para agrupar arquivos relacionados, e agem como um namespace para
os arquivos dentro deles. Como um exemplo concreto, o arquivo foo.txt pode
existir em ambos os diretórios /home/greg e /home/other,
mas duas cópias de foo.txt não podem coexistir em um mesmo diretório. Além
disso, para acessar o arquivo foo.txt fora do
diretório /home/greg, o nome do diretório deve ser prefixado ao nome
do arquivo usando o separador de diretórios para obter /home/greg/foo.txt. Esse
mesmo princípio se estende a namespaces no mundo da programação.
No mundo PHP, os namespaces são projetados para resolver dois problemas que os autores
de bibliotecas e aplicações encontram ao criar elementos de código reutilizáveis,
como classes ou funções:
Colisões de nomes entre o código criado e
classes/funções/constantes internas do PHP ou classes/funções/constantes de terceiros.
Capacidade de criar apelidos (ou encurtar) Nomes_Extralongos projetados para aliviar o primeiro problema,
melhorando a legibilidade do código-fonte.
Os Namespaces do PHP fornecem uma maneira de agrupar classes, interfaces,
funções e constantes relacionadas. Aqui está um exemplo da sintaxe de namespace em PHP:
Exemplo da sintaxe de namespace
]]>
Nomes de namespace não diferenciam maiúsculas de minúsculas.
O nome do namespace PHP e os nomes compostos que começam
com esse nome (como PHP\Classes) são reservados para uso interno da linguagem
e não devem ser usados no código criado pelo usuário.
Definindo namespacesNamespaces
Embora qualquer código PHP válido possa estar contido em um namespace, apenas os seguintes
tipos de código são afetados por namespaces: classes (incluindo abstratas, traits e enumerações), interfaces,
funções e constantes.
Namespaces são declarados usando a palavra-chave namespace.
Um arquivo contendo um namespace deve declarar o namespace
no início do arquivo antes de qualquer outro código - com uma exceção: a
palavra-chave .
Declarando um único namespace
]]>
Nomes totalmente qualificados (ou seja, nomes que começam com uma barra invertida) não são permitidos em declarações
de namespace, por serem construções interpretadas como expressões de namespace relativos.
A única construção de código permitida antes de uma declaração de namespace é a
declaração declare, para definir a codificação de um arquivo-fonte. Além disso,
nenhum código não-PHP pode preceder uma declaração de namespace, incluindo espaço em branco extra:
Declarando um único namespace
]]>
Além disso, ao contrário de qualquer outra construção do PHP, o mesmo namespace pode ser definido
em vários arquivos, permitindo a divisão do conteúdo de um namespace no sistema de arquivos.
Declarando sub-namespacesSub-namespaces
Assim como diretórios e arquivos, os namespaces do PHP podem especificar
uma hierarquia de namespaces. Assim, um namespace pode ser definido com
subníveis.
Declarando um único namespace com hierarquia
]]>
O exemplo acima cria a constante MeuProjeto\Nivel\SubNivel\CONEXAO_OK,
a classe MeuProjeto\Nivel\SubNivel\Conexao e a função
MeuProjeto\Nivel\SubNivel\conectar.
Definindo vários namespaces no mesmo arquivoDefinindo vários namespaces no mesmo arquivo
Vários namespaces também podem ser declarados no mesmo arquivo. Existem duas sintaxes
permitidas.
Declarando vários namespaces, sintaxe de combinação simples
]]>
Essa sintaxe não é recomendada para combinar namespaces em um único arquivo.
Em vez disso, é recomendado usar a sintaxe alternativa de colchetes.
Declarando vários namespaces, sintaxe de colchetes
]]>
É altamente desaconselhado como prática de programação combinar vários namespaces no
mesmo arquivo. O principal caso de uso é combinar vários scripts PHP no mesmo
arquivo.
Para combinar código global sem namespace com código com namespace, apenas a sintaxe de colchetes é
suportada. O código global deve ser
encapsulado em uma declaração de namespace sem nome de namespace, como em:
Declarando vários namespaces e código sem namespace
]]>
Nenhum código PHP pode existir fora dos colchetes do namespace, exceto uma declaração
declare de abertura.
Declarando vários namespaces e código sem namespace
]]>
Usando namespaces: FundamentosFundamentos
Antes de discutir o uso de namespaces, é importante entender como o PHP
sabe qual elemento de namespace seu código está solicitando. Uma analogia simples pode ser feita
entre os namespaces do PHP e um sistema de arquivos. Existem três maneiras de acessar um arquivo em um
sistema de arquivos:
Nome de arquivo relativo como foo.txt. Será resolvido para
diretorioatual/foo.txt onde diretorioatual é o
diretório ocupado atualmente. Então, se o diretório atual for
/home/foo, o nome será resolvido para /home/foo/foo.txt.
Nome de caminho relativo como subdiretorio/foo.txt. Será resolvido
para diretorioatual/subdiretorio/foo.txt.
Nome de caminho absoluto como /main/foo.txt. Será resolvido
para /main/foo.txt.
O mesmo princípio pode ser aplicado a elementos com namespace no PHP. Por
exemplo, um nome de classe pode ser referenciado de três maneiras:
Nome não qualificado ou nome de classe sem prefixo como
$a = new foo(); ou
foo::metodoestatico();. Se o namespace atual for
namespaceatual, ele será resolvido para
namespaceatual\foo. Se
o código for global, sem namespace, ele será resolvido para foo.
Uma ressalva: nomes não qualificados para funções e constantes
serão resolvidos para funções e constantes globais se a função ou constante com namespace
não for definida. Veja Usando namespaces:
recorrendo a funções/constantes globais para obter detalhes.
Nome qualificado ou um nome de classe prefixado como
$a = new subnamespace\foo(); ou
subnamespace\foo::metodoestatico();. Se o namespace atual for
namespaceatual, ele será resolvido para
namespaceatual\subnamespace\foo. Se
o código for global, sem namespace, ele será resolvido para subnamespace\foo.
Nome totalmente qualificado ou um nome prefixado com um operador de prefixo global como
$a = new \namespaceatual\foo(); ou
\namespaceatual\foo::metodoestatico();. Ele sempre será resolvido
para o nome literal especificado no código, namespaceatual\foo.
Aqui está um exemplo dos três tipos de sintaxe em código real:
arquivo1.php
]]>
arquivo2.php
]]>
Note que para acessar qualquer classe,
função ou constante global, um nome totalmente qualificado pode ser usado, como
\strlen ou \Exception ou
\INI_ALL.
Acessando classes, funções e constantes globais em um namespace
]]>
Namespaces e recursos de linguagem dinâmicaNamespaces e recursos de linguagem dinâmica
A implementação de namespaces do PHP é influenciada por sua natureza dinâmica como linguagem
de programação. Assim, para converter código como o exemplo a seguir em código com namespace:
Acessando elementos dinamicamenteexemplo1.php:
]]>
Deve-se usar o nome totalmente qualificado (nome da classe prefixado com o namespace).
Observe que, como não há diferença entre um nome qualificado e um nome totalmente qualificado
em um nome de classe, nome de função ou nome de constante dinâmico, a barra invertida inicial não
é necessária.
Acessando dinamicamente elementos com namespace
]]>
Certifique-se de ler a nota sobre
escapamento de namespaces em strings.
Palavra-chave namespace e constante __NAMESPACE__Palavra-chave namespace e __NAMESPACE__
O PHP suporta duas maneiras de acessar elementos de forma abstrata dentro do namespace atual,
a constante mágica __NAMESPACE__ e a palavra-chave
namespace.
O valor de __NAMESPACE__ é uma string que contém o nome do namespace
atual. Em código global, sem namespace, ela contém uma string vazia.
Exemplo de __NAMESPACE__, código com namespace
]]>
Exemplo de __NAMESPACE__, código global
]]>
A constante __NAMESPACE__ é útil para construir nomes de forma
dinâmica, por exemplo:
Usando __NAMESPACE__ para construção dinâmica de nomes
]]>
A palavra-chave namespace pode ser usada para solicitar explicitamente
um elemento do namespace atual ou um subnamespace. Ela é o equivalente
para namespaces do operador self para classes.
O operador namespace, em um namespace
]]>
O operador namespace, em código global
]]>
Usando namespaces: Apelidando/ImportandoApelidando e Importando
A capacidade de se referir a um nome totalmente qualificado externo com um apelido, ou importação,
é um recurso importante dos namespaces. Isso é semelhante à
capacidade dos sistemas de arquivos baseados em Unix de criar links simbólicos para um arquivo ou diretório.
O PHP pode apelidar ou importar constantes, funções, classes, interfaces, traits, enums e namespaces.
A criação de apelidos é realizada com o operador use.
Aqui está um exemplo mostrando todos os 5 tipos de importação:
Importando ou apelidando com o operador use
]]>
Note que para nomes com namespaces (nomes de namespaces totalmente qualificados contendo
o separador de namespace, como Foo\Bar, em oposição a nomes globais sem
separadores, como FooBar), a barra invertida inicial não é necessária e não
é recomendada, pois nomes importados precisam
ser totalmente qualificados e não são processados em relação ao namespace atual.
O PHP também suporta um atalho de conveniência para colocar várias instruções use
na mesma linha.
Importando ou criando apelidos com várias declarações use combinadas
]]>
A importação é realizada em tempo de compilação e por isso, não afeta classes, funções
ou nomes de constantes gerados dinamicamente.
Importação e nomes dinâmicos
]]>
Além disso, a importação afeta apenas nomes não qualificados e qualificados. Nomes totalmente
qualificados são absolutos e não são afetados pelas importações.
Importação e nomes completamente qualificados
]]>
Regras de escopo para importação
A palavra-chave use precisa ser declarada no
escopo mais externo do arquivo (o escopo global) ou dentro de declarações
de namespaces. Isso ocorre por a importação ser realizada em tempo de
compilação e não em tempo de execução, portanto, não pode ter escopo de bloco. O exemplo
a seguir mostra um uso inválido da palavra-chave
use:
Regra de importação inválida
]]>
As regras de importação são por arquivo, o que significa que os arquivos incluídos
NÃO herdarão as regras de importação do arquivo pai.
Declarações use em grupo
Classes, funções e constantes importadas do
mesmo &namespace; podem ser agrupadas numa única declaração
&use.namespace;.
Espaço GlobalEspaço Global
Quando um namespace não é definido, todas as definições de classes e funções são
colocadas no espaço global, como era no PHP antes de os namespaces serem
suportados. Prefixar um nome com \ especificará que
o nome é necessário no espaço global, mesmo no contexto do
namespace.
Usando a especificação do espaço global
]]>
Usando namespaces: recorrendo ao espaço global para funções e constantesRecorrendo ao espaço global
Dentro de um namespace, quando o PHP encontra um nome não qualificado em um nome de classe, função ou
contexto de constante, eles são resolvidos com diferentes prioridades. Nomes de classe sempre
são resolvidos para o nome do namespace atual. Portanto, para acessar classes internas ou classes de usuário
sem namespace, deve-se referir a elas com o nome totalmente qualificado como em:
Acessando classes globais em um namespace
]]>
Para funções e constantes, o PHP recorrerá a funções ou constantes globais
se a função ou constante com namespace não existir.
Recorrendo a funções/constantes globais em um namespace
]]>
Regras de resolução de nomesRegras de resolução de nomes
Para efeitos destas regras de resolução, aqui estão algumas definições importantes:
Definições de nomes de namespaceNome 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:
Nomes totalmente qualificados sempre são resolvidos para o nome sem separador de namespace à esquerda.
Por exemplo, \A\B será resolvido para A\B.
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.
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.
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.
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.
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.
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:
Procura pela função no namespace atual:
A\B\foo().
Tenta encontrar e chamar a função globalfoo().
Resoluções de nomes ilustradas
]]>
Perguntas Frequentes: Coisas que você precisa saber sobre namespacesPerguntas Frequentes
Estas perguntas frequentes são divididas em duas seções: perguntas comuns e alguns detalhes de
implementação úteis para entender os pormenores.
Primeiro, as perguntas comuns.
Se não usar namespaces, devo
me importar com esta documentação?
Como usar classes internas ou globais
em um namespace?
Como usar classes,
funções ou constantes de namespace em seu próprio namespace?
Como nomes como \meu\nome ou \nome
são resolvidos?
Como um nome como
meu\nome é resolvido?
Como um nome de classe não qualificado
como nome é resolvido?
Como um nome de função
não qualificado ou nome de constante não qualificado
como nome é resolvido?
Há alguns detalhes de implementação dos namespaces úteis para
entendê-los melhor.
Nomes de importação não devem entrar em conflito com
classes definidas no mesmo arquivo
Namespaces aninhados não são permitidos.
Nomes de namespace dinâmicos (identificadores
entre aspas) devem escapar a barra invertida
Constantes indefinidas referenciadas
usando qualquer barra invertida geram erro fatal
Não é possível substituir
as constantes especiais &null;, &true; ou &false;
Se não usar namespaces, devo me importar com esta documentação?
Não. Namespaces não afetam nenhum código existente de forma alguma, ou qualquer
código ainda a ser escrito que não contenha namespaces. Você pode
escrever este código se desejar:
Acessando classes globais fora de um namespace
]]>
O exemplo acima é equivalente ao seguinte código:
Acessando classes globais fora de um namespace
]]>
Como usar classes internas ou globais em um namespace?Acessando classes internas em namespaces
]]>
Como usar classes, funções ou constantes de namespace em seu próprio
namespace?
Acessando classes, funções ou constantes internas em namespaces
]]>
Como nomes como \meu\nome ou \nome
são resolvidos?
Nomes que começam com uma barra invertida (\) sempre são resolvidos
para seu conteúdo exato, então \meu\nome é o mesmo que meu\nome
e \Exception é o mesmo que Exception.
Nomes totalmente qualificados
]]>
Como um nome como meu\nome é resolvido?
Nomes que contêm barra invertida, mas não começam com uma barra invertida, como
meu\nome podem ser resolvidos de duas maneiras diferentes.
Se houver
uma instrução de importação que cria o apelido meu para outro nome, então
o apelido da importação será aplicado ao meu em meu\nome.
Caso contrário, o nome do namespace atual será prefixado a meu\nome.
Nomes qualificados
]]>
Como um nome de classe não qualificado como nome é resolvido?
Nomes de classes que não contêm barra invertida como
nome podem ser resolvidos de duas maneiras diferentes.
Se houver
uma instrução de importação que cria o apelido nome para outro nome, então
o apelido da importação será aplicado.
Caso contrário, o nome do namespace atual será prefixado a nome.
Nomes de classe não qualificados
]]>
Como um nome de função não qualificado ou nome de constante não qualificado
como nome é resolvido?
Nomes de funções ou constantes que não contêm barra invertida como
nome podem ser resolvidos de duas maneiras diferentes.
Primeiro, o nome do namespace atual será prefixado a nome.
Finalmente, se a constante ou função nome não existir
no namespace atual, uma constante ou função global nome
será usada se existir.
Nomes de funções ou constantes não qualificados
]]>
Nomes de importação não devem entrar em conflito com classes definidas no mesmo arquivo
As seguintes combinações de script são válidas:
arquivo1.php
]]>
outra.php
]]>
arquivo2.php
]]>
Não há conflito de nomes, mesmo que a classe MinhaClasse exista
dentro do namespace minha\coisa, porque a definição de MinhaClasse está
em um arquivo separado. No entanto, o próximo exemplo causa um erro fatal de conflito de nomes
porque MinhaClasse está definida no mesmo arquivo que a declaração use.
]]>
Namespaces aninhados não são permitidos
O PHP não permite aninhar namespaces.
]]>
No entanto, é fácil simular namespaces aninhados da seguinte forma:
]]>
Nomes de namespace dinâmicos (identificadores entre aspas) devem escapar a barra invertida
É muito importante perceber que, como a barra invertida é usada como um caractere de escape
dentro de strings, ela sempre deve ser duplicada quando usada em uma string. Caso contrário,
existe o risco de consequências não desejadas:
Perigos do uso de nomes com namespace em uma string com aspas duplas
]]>
Dentro de uma string com aspas simples, a sequência de escape da barra invertida é muito mais segura de usar, mas
ainda é uma prática recomendada escapar as barras invertidas em todas as strings.
Constantes indefinidas referenciadas usando qualquer barra invertida geram erro fatal
Qualquer constante indefinida não qualificada como FOO gerará
um alerta explicando que o PHP assumiu que FOO era o valor
da constante. Qualquer constante, qualificada ou totalmente qualificada, que contenha
uma barra invertida produzirá um erro fatal se não for encontrada.
Constantes não definidas
]]>
Não é possível substituir as constantes especiais &null;, &true; ou &false;
Qualquer tentativa de definir uma constante de namespace que seja uma constante especial nativa
resultará em um erro fatal.
Constantes não definidas
]]>