Namespaces possibilitam o agrupamento de classes, interfaces, funções e constantes, visando evitar o conflito entre seus nomes, atuando como um encapsulador para estes itens, seu funcionamento é equivalente ao de diretórios em sistemas operacionais, onde dois arquivos de mesmo nome não podem existir em um único diretório, mas nada impede a existência de dois arquivos de mesmo nome localizados em diretórios distintos, este mesmo princípio é aplicado no PHP através de namespaces, ao utilizar este recurso temos mais liberdade na hora de criar classes, funções e etc, não sendo mais necessário utilizar prefixo para diferenciar seus nomes.
Este recurso está disponível a partir da versão 5.3 do PHP.
Definindo namespaces
Namespaces são declarados utilizando a palavra-chave namespace. Um arquivo que contenha namespace deve realizar a declaração do mesmo logo no inicio, antes de qualquer código, com exceção de comentários, espaços em branco e declare.
Seguindo o pensamento dos diretórios utilizado na introdução deste artigo, o recurso de namespaces também permite adicionar nomes com estrutura hierárquica, ou seja, sub-namespaces.
Declarando diversos namespaces em um arquivo
Embora não seja uma prática recomendada, podemos declarar mais de um namespace no mesmo arquivo, confira:
(1) Combinação de sintaxe
(2) Sintaxe entre colchetes
(3) Namespace indefinido
Utilizando namespaces
Antes de utilizar namespaces no PHP, é importante entender como o PHP identifica o contexto do qual o elemento será solicitado. Para isso vamos realizar uma analogia de como os sistemas operacionais acessam arquivos.
Há três maneiras de acessar um arquivo em sistemas operacionais:
- Nome de arquivo relativo, por exemplo: foo.txt, resultado: diretorioatual/foo.txt
- Nome de caminho relativo, por exemplo: subdiretorio/foo.txt, resultado: diretorioatual/subdiretorio/foo.txt
- Nome de caminho absoluto, por exemplo: /main/foo.txt, resultado: /main/foo.txt
O mesmo princípio pode ser aplicado a elementos utilizando namespace no PHP, por exemplo, uma classe pode ser solicitada de três maneiras.
(1) Nome não qualificado, ex: $var = new User;
Caso o namespace atual seja Project\Model, será solicitado Project\Model\User. Se o código for global, ou seja, sem namespace definido, irá solicitar User.
(2) Nome qualificado, ex: $var = new Model\User();
Caso o namespace atual seja Project, será solicitado Project\Model\User. Se o código for global, ou seja, sem namespace definido, irá solicitar Model\User.
(3) Nome absoluto, ex: $var = new \Project\Model\User();
Este tipo sempre irá solicitar pelo nome absoluto \Project\Model\User.
Aliasing / Importing
Uma caracteristica importante ao trabalhar com namespaces é a possibilidade de importar e atribuir apelidos. A palavra-chave use é utilizada para importar classes, interfaces ou namespaces através de seus nomes, não é possível importar funções ou constantes. Para adicionar apelidos, utilizamos a palavra-chave as, escolhendo um nome mais acessível, ou seja, um apelido, existem duas maneiras de realizar importações:
(1) Importação simples
(2) Múltiplas importações
O PHP oferece um atalho para realizar múltiplas importações na mesma linha, onde cada importação é separada através de uma virgula.
A importação não afeta nomes dinâmicos de funções, classes ou constantes.
Além disso, a importação só afeta nomes não qualificados e qualificados, nomes absolutos não são afetados por importações.
A palavra-chave use deve ser declarada em escopo global ou dentro de declarações de namespace.
Constante NAMESPACES
A constante mágica NAMESPACE é uma constante dinâmica que possui seu valor baseado no namespace corrente, ou seja, seu valor irá variar de acordo com o escopo/namespace no qual for utilizada.
A palavra-chave namespace também pode ser utilizada para solicitar um elemento do namespace atual ou de um sub-namespace.
Caso o arquivo não tenha namespace, ou seja, um arquivo global, o valor da constante NAMESPACE será uma string vazia.
Global space
Sem a definição de um namespace, todas as definições de classes, interfaces, funções e constantes são colocadas no escopo global, como era no PHP antes dos namespaces serem suportados.
Prefixando o nome do elemento com \ especificará que o elemento é requerido do escopo global até mesmo no contexto de namespace.
Utilizando autoload para carregar arquivos
Utilizar autoload nunca foi tão fácil, principalmente se você estruturar seus arquivos em diretórios nomeados de acordo com seus namespaces, por exemplo, no namespace “Project\Model” existe uma classe nomeada User, se estruturarmos os arquivos de maneira que User.php fique no diretório “Project/Model”, ou seja, “Project/Model/User.php”, a única coisa que precisamos fazer é registrar o autoloader padrão:
Mas como nada é perfeito, a solução acima não funciona em servidores linux, embora algumas pessoas já tenham solicitado reparo, parece que o problema ocorre por causa do path separator, o autoloader padrão tenta importar arquivos utilizando o path separator \ utilizado nos namespaces, o que é inválido para sistemas Linux/Unix, mas no windows funciona, enfim, enquanto esperamos essa correção precisamos definir um callback(função) que contorne essa situação e funcione em qualquer servidor, confira:
Caso seu projeto tenha uma estrutura de arquivos personalizada, podemos alterar a função conforme for necessário, por exemplo, projetos que utilizam classes com extensão “.class.php”:
No stackoverflow existe um tópico sobre, Namespace Autoload works under windows, but not on Linux, onde podemos ler um pouco sobre essa situação, inclusive foi compartilhada uma solução mais robusta.
Diferente do método mágico __autoload(), spl_autoload_register() permite a definição de várias funções autoload, formando uma fila de funções, percorrendo cada uma das funções seguindo a ordem de definição.
Antes de começar a utilizar namespaces, de uma olhada nas regras utilizadas para identificar de qual escopo/namespace deverá ser solicitada sua classe, interface, função ou constante.
Trabalhando com namespaces no PHP
Baseado em alguns dos exemplos acima, criei um exemplo completo para demonstrar o funcionamento de namespaces no php, visualize ou efetue download do exemplo.