Namespaces Visão geral de Namespaces Visã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 namespaces Namespaces 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-namespaces Sub-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 arquivo Definindo 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: Fundamentos Fundamentos 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âmica Namespaces 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 dinamicamente exemplo1.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/Importando Apelidando 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 <literal>use</literal> em grupo Classes, funções e constantes importadas do mesmo &namespace; podem ser agrupadas numa única declaração &use.namespace;. Espaço Global Espaç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 constantes Recorrendo 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 nomes Regras de resolução de nomes 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: 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 global foo(). Resoluções de nomes ilustradas ]]> Perguntas Frequentes: Coisas que você precisa saber sobre namespaces Perguntas 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 <literal>\meu\nome</literal> ou <literal>\nome</literal> 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 <literal>meu\nome</literal> é 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 <literal>nome</literal> é 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 <literal>nome</literal> é 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 ]]>