Entendendo namespaces no PHP
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.
<?php namespace Project; // ...
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.
<?php namespace Project\Model; // ...
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
<?php namespace Project; class User {} namespace AnotherProject; class User {} ?>
2. Sintaxe entre colchetes
<?php namespace Project { class User {} } namespace AnotherProject { class User {} } ?>
3. Namespace indefinido
<?php namespace Project { class User {} } // Global scope namespace { class User {} } ?>
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.
// Example - Namespace scope namespace Project\Model; class User {} $var = new User; // Resultado: Project\Model\User // Example - Global scope class User {} $var = new User; // Resultado: 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.
// Example - Namespace scope namespace Project; $var = new Model\User; // Resultado: Project\Model\User // Example - Global scope $var = new Model\User; // Resultado: Model\User
3. Nome absoluto, ex: $var = new \Project\Model\User();
Este tipo sempre irá solicitar pelo nome absoluto \Project\Model\User.
// Example - Namespace scope namespace Project; $var = new \Project\Model\User; // Resultado: Project\Model\User // Example - Global scope $var = new \Project\Model\User; // Resultado: 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
use Project\Model\User; // É o mesmo que: use Project\Model\User as User; $var = new User; // Resultado: Project\Model\User
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.
use Project\Model\User, Project\Model\Post as Article; $var = new Article; // Resultado: Project\Model\Post
A importação não afeta nomes dinâmicos de funções, classes ou constantes.
use Project\Model\Post; $var = new Post; // Resultado: Project\Model\Post $name = 'Post'; $var = new $name; // Resultado: Post
Além disso, a importação só afeta nomes não qualificados e qualificados, nomes absolutos não são afetados por importações.
use Project\Model\Post; $var = new Post; // Resultado: Project\Model\Post $var = new \Post; // Resultado: Post
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.
<?php namespace Project\Model; echo __NAMESPACE__; // Resultado: Project\Model ?>
A palavra-chave namespace também pode ser utilizada para solicitar um elemento do namespace atual ou de um sub-namespace.
<?php namespace Project $var = new namespace\Model\User; // Resultado: Project\Model\User ?>
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.
// file User.php class User {} // Example - Namespace scope namespace Project\Model; require_once("User.php"); $var = new User; // Resultado: Project\Model\User // Example - Global scope require_once("User.php"); $var = new User; // Resultado: User
Prefixando o nome do elemento com \ especificará que o elemento é requerido do escopo global até mesmo no contexto de namespace.
// file User.php class User {} // Example - Namespace scope namespace Project\Model; require_once("User.php"); $var = new \User; // Resultado: User // Example - Global scope require_once("User.php"); $var = new \User; // Resultado: User
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:
<?php spl_autoload_extensions(".php"); spl_autoload_register(); ?>
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:
<?php spl_autoload_register(function ($class) { require_once(str_replace('\\', '/', $class . '.php')); }); ?>
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”:
<?php spl_autoload_register(function ($class) { require_once(str_replace('\\', '/', $class . '.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.
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.
Resultado esperado para o exemplo:

Referência(s):
http://www.php.net/manual/en/language.namespaces.php
http://php.net/manual/en/language.oop5.autoload.php
http://php.net/manual/pt_BR/function.spl-autoload-register.php
http://stackoverflow.com/questions/2862133/namespace-autoload-works-under-windows-but-not-on-linux
Comentários 19
Andrey Knupp Vital
07/11/2011 às 14:33
Fala Diogo, Beleza .. ?
Bom artigo, parabéns, eu vejo 2 casos em que o namespace se aplica, um na organização de objetos, outro em agrupamento, quando você tem um relacionamento grande, como o MVC, e trabalha com Gateways, e outros serviços em que o modelo de negócios está envolvido, você normalmente separa às camadas, alterando a nomenclatura da classe, como se estivesse um prefixo, exemplo: CustomersModel, CustomersGateway, CustomersController … e então podemos aplicar o namespace normalmente como se estivéssemos fazendo um pacote que é apenas reservado para manipulação de clientes, e teríamos tudo que é relacionado definindo esse namespace !
Você já viu o Phar ? http://br.php.net/Phar .. tem como criar pacotes semelhantes ao do Java utilizando este recurso ..
http://imasters.com.br/artigo/16721/php/phar-distribuindo-aplicacao-php-em-um-unico-arquivo
Diogo Matheus
07/11/2011 às 17:04
Fala Andrey,
Estava conversando sobre isso com alguns conhecidos, parece que o Zend Studio já está dando suporte a namespaces, vou dar uma olhada depois, assim que as IDEs começarem a apoiar isso vai crescer, eu não consigo imaginar o Java sem os packages por exemplo.
Sobre o Phar eu já havia dado uma olhada, ainda não testei, vou dar uma conferida assim que puder, mas a ideia é muito legal, principalmente para aplicações comerciais, mas ainda não existe um gerador de Phar? acho que fecharia com chave de ouro.
Abraço
Rafael
20/03/2014 às 11:24
Ótimo tutorial, muito obrigado!
Angelito
31/07/2014 às 11:27
Ótimo post, parabéns. ;)
Namespaces no PHP
04/10/2014 às 10:48
[…] http://www.diogomatheus.com.br/blog/php/entendendo-namespaces-no-php/ […]
Vinicius
02/12/2014 às 12:09
Obrigado pelo artigo Diogo.
Para quem vem de C#/Java/C++ é um alento saber que namespaces podem ser definidos dentro de chaves!
Diogo Matheus
26/02/2015 às 15:15
Rafael, Angelito e Vinicius,
Obrigado pelo comentário.
Rafael
12/08/2015 às 21:06
Grato pelo artigo Diogo! Está me ajudando muito no estudo para o exame da ZCPE. Abração!
Diogo Matheus
02/11/2015 às 20:28
Obrigado pelo comentário Rafael.
Boa sorte no exame.
PHP do jeito certo | Diogo Matheus
23/11/2015 às 08:45
[…] que envolve padrões de projeto e alguns recursos essenciais, além dos destaques da linguagem como namespaces e […]
PHP do jeito certo -
03/12/2015 às 14:02
[…] que envolve padrões de projeto e alguns recursos essenciais, além dos destaques da linguagem como namespaces e […]
Roger
14/07/2016 às 19:31
Primeiramente, parabéns pelo tópico Diogo, achei muito interessante e fácil de entender, está me ajudando muito.
Apenas uma dúvida, tem diferença entre utilizarmos o “use” para importar uma classe ou o “require_once”?
Grande abraço!
Diogo Matheus
17/07/2016 às 13:19
Roger,
Para o objetivo final não, que é simplesmente usar classes em outro arquivo normalmente, também não existe diferença significativa em performance, alguns dizem que existe uma diferença mínima a favor do require_once.
O mais interessante de fazer uso de namespace são os benefícios no aspecto de estruturação do projeto, tirar proveito do conceito de autoloading e facilitar nossa vida para evitar conflitos entre diferentes bibliotecas de código.
No geral tanto faz qual opção você vai usar, mas namespace acaba sendo uma opção mais poderosa e bem vista a longo prazo, principalmente para projetos de médio e grande porte.
Marcio Leandro
21/07/2016 às 14:45
Muito bom artigo, parabéns.
Vitor Pereira
14/12/2016 às 15:57
Salve Diogo,
Queria tirar uma dúvida, meus diretórios começam com números, exemplo, 10.manutenção, 37.estoque, 1.classes, e quando utilizo o namespace ele não aceita o começo com números, tem alguma forma de utilizar dessa maneira?
Migrando do Codeigniter para o Laravel 5.3 (Parte 2) – Blog Bugginho Academy
17/12/2016 às 20:36
[…] Lembra que eu falei que o Laravel exige um pouco mais de conhecimento que o Codeigniter? Bem, aqui a gente já percebe isso. Note que na linha 3, o Laravel utilizou um recurso muito útil do PHP chamado namespace, caso você não conheça esse recurso, aconselho que você dê uma lida na documentação da linguagem ou nesse artigo do Diogo Matheus. […]
Caio
17/04/2017 às 09:30
Olá amigo, Infelizmente pra quem está estrado na área de php,não deu pra entender nada! somente uso de palavras complexas.
João Paulo
10/06/2017 às 22:15
Estou implementando uma library e ela tem DIVERSAS subpastas que o autoload nao está incluindo. Alguem tem uma luz?
Emerson Murilo
03/03/2020 às 17:34
Excelente artigo.