PHP Namespaces
Quando um projeto cresce, os nomes começam a se repetir: a lojinha da Ana tem uma classe Produto, o blog dela também quer uma classe Produto (o produto que aparece num post), e uma biblioteca baixada da internet pode trazer mais uma. O PHP não aceita duas classes com o mesmo nome. Os namespaces (em português, "espaços de nomes") resolvem isso: cada parte do código ganha um "sobrenome", e Loja\Produto deixa de brigar com Blog\Produto.
- Por que duas classes com o mesmo nome dão erro, e como o namespace resolve.
- A declaração
namespacee o nome completo de uma classe (Loja\Produto). - Os três jeitos de escrever um nome: não qualificado, qualificado e totalmente qualificado (com
\na frente). - O
use(importar), ouse … as(apelido), ouse functione ouse const. - Por que
strlenfunciona dentro de um namespace, masnew DateTimenão (e o que o\faz). - A regra "um namespace por arquivo" e a organização em pastas que prepara o autoload.
Esta aula supõe que você já sabe criar classes e objetos e juntar arquivos com include e require. Todas as saídas foram geradas no PHP 8.5 do laboratório, na máquina da Ana (ana@notebook).
A ideia: sobrenomes para o código
Numa sala de aula com duas alunas chamadas Maria, a professora passa a usar o sobrenome: "Maria Souza" e "Maria Lima". Ninguém mudou de nome; só ficou claro de quem se está falando.
O namespace é o sobrenome do código. Uma classe Produto declarada no namespace Loja passa a se chamar, por extenso, Loja\Produto. Outra, no namespace Blog, se chama Blog\Produto. São duas classes diferentes, que convivem no mesmo programa.
| Dia a dia | PHP |
|---|---|
| Sobrenome da família | O namespace: Loja |
| Nome | O nome da classe: Produto |
| Nome completo, "Maria Souza" | O nome totalmente qualificado: \Loja\Produto |
| Dentro de casa, todo mundo chama só de "Maria" | Dentro do namespace Loja, basta escrever Produto |
| Apelido, para não confundir | use Blog\Produto as Post; |
O separador é a barra invertida \ (a mesma dos caminhos do Windows), e não a barra normal /. Ela foi escolhida porque não tinha outro uso no PHP.
O problema: dois Produto no mesmo programa
A Ana tem dois arquivos. O loja.php declara a classe da lojinha:
<?php
class Produto
{
public function __construct(public string $nome) {}
}
O blog.php declara outra classe com o mesmo nome, para os produtos citados nos posts:
<?php
class Produto
{
public string $titulo = "Post patrocinado";
}
Um terceiro arquivo usa os dois:
<?php require 'loja.php'; require 'blog.php'; echo "fim\n";
$ php conflito.php
Fatal error: Cannot redeclare class Produto (previously declared in /home/ana/ns/loja.php:2) in /home/ana/ns/blog.php on line 2
Stack trace:
#0 /home/ana/ns/conflito.php(3): require()
#1 {main}
A mensagem diz: "não é possível declarar de novo a classe Produto (ela já foi declarada em loja.php, linha 2), em blog.php, linha 2". O programa parou ali: o fim nunca apareceu. O stack trace ("rastro da pilha") mostra o caminho: foi o require da linha 3 de conflito.php que carregou o arquivo com o problema.
Sem namespaces, a única saída seria renomear uma das classes para algo como BlogProduto. Era assim que o PHP antigo fazia (nomes compridos como Zend_Db_Table_Abstract). Desde o PHP 5.3 existe um jeito melhor.
Declarando um namespace
A primeira linha de código do arquivo diz a qual namespace ele pertence:
<?php
namespace Loja;
class Produto
{
public function __construct(public string $nome) {}
}
function preco(float $valor): string
{
return "R$ " . number_format($valor, 2, ",", ".");
}
const MOEDA = "BRL";
$p = new Produto("Caneca");
echo $p->nome, "\n";
echo preco(19.9), "\n";
echo MOEDA, "\n";
echo Produto::class, "\n";
echo __NAMESPACE__, "\n";
- namespace Loja;
- "Tudo o que for declarado daqui para baixo pertence ao namespace
Loja." Termina com ponto e vírgula, como uma instrução. - class Produto
- O nome completo dessa classe passa a ser
Loja\Produto. - function preco
- Funções também entram no namespace: o nome completo é
Loja\preco. - const MOEDA
- Constantes criadas com
consttambém:Loja\MOEDA. (Constantes criadas comdefine()não entram no namespace, a não ser que você escreva o nome completo dentro dodefine.) - new Produto(…)
- Dentro do próprio namespace, basta o nome curto. O PHP completa sozinho para
Loja\Produto. - Produto::class
- Devolve o nome completo da classe, como texto. Ótimo para conferir onde uma classe "mora".
- __NAMESPACE__
- Constante mágica com o nome do namespace atual (vazia fora de um namespace).
$ php n1.php Caneca R$ 19,90 BRL Loja\Produto « o nome completo da classe Loja « o namespace atual
Repare que nada muda na hora de usar a classe dentro do arquivo: o namespace só acrescenta o "sobrenome" por fora. Variáveis ($p) nunca entram em namespaces; só classes (e também interfaces, traits e enums), funções e constantes.
Nomes com várias partes
Um namespace pode ter vários níveis, separados por \, como pastas dentro de pastas: namespace Loja\Pagamento;, namespace AnaSilva\Blog\Comentarios;. O costume é começar pelo nome do autor ou da empresa (o "fornecedor", vendor em inglês) e depois o projeto. Você vai ver isso de novo no Composer.
Usando a classe de outro arquivo
Agora a Ana organiza os arquivos em pastas, uma para cada namespace:
ns2/
├── index.php
└── src/
├── Blog/
│ └── Produto.php « namespace Blog
└── Loja/
├── Produto.php « namespace Loja
└── funcoes.php « namespace Loja (funções e constante)
<?php
namespace Loja;
class Produto
{
public function __construct(
public string $nome,
public float $preco,
) {}
}
<?php
namespace Blog;
class Produto
{
public function __construct(public string $titulo) {}
}
O index.php não tem namespace (está no "namespace global", o espaço sem sobrenome). Para usar as classes, ele pode escrever o nome completo, com uma barra na frente:
<?php
require __DIR__ . '/src/Loja/Produto.php';
$caneca = new \Loja\Produto("Caneca", 19.9);
$outra = new Loja\Produto("Camiseta", 49.9);
echo $caneca->nome, " e ", $outra->nome, "\n";
$ php fqn.php Caneca e Camiseta
As duas formas funcionaram, mas por motivos diferentes. Para entender, você precisa conhecer os três tipos de nome.
Os três tipos de nome
| Tipo | Exemplo | Como o PHP lê |
|---|---|---|
| Não qualificado (sem barra nenhuma) | Produto | "Produto do namespace onde eu estou" (ou o que um use disser) |
| Qualificado (tem barra no meio) | Loja\Produto | "Loja\Produto a partir do namespace onde eu estou" (é relativo, como um caminho de pasta sem / na frente) |
| Totalmente qualificado (começa com barra) | \Loja\Produto | "Exatamente Loja\Produto, a partir da raiz". Nunca muda, esteja onde estiver |
No fqn.php, como o arquivo está no namespace global, Loja\Produto "a partir do global" é o mesmo que \Loja\Produto. Mas veja o que acontece quando o arquivo tem o seu próprio namespace:
<?php
namespace App;
require __DIR__ . '/src/Loja/Produto.php';
$caneca = new Loja\Produto("Caneca", 19.9);
$ php relativo.php
Fatal error: Uncaught Error: Class "App\Loja\Produto" not found in /home/ana/ns2/relativo.php:6
Stack trace:
#0 {main}
thrown in /home/ana/ns2/relativo.php on line 6
O nome qualificado foi lido a partir de App, e virou App\Loja\Produto, que não existe. A barra na frente (new \Loja\Produto) ou um use resolvem. A comparação com pastas ajuda: \Loja\Produto é como /home/ana/foto.png (caminho absoluto); Loja\Produto é como Documentos/foto.png (depende de onde você está).
use: importar um nome
Escrever \Loja\Produto toda vez cansa. O use ("usar") cria um atalho: depois de use Loja\Produto;, o nome curto Produto, naquele arquivo, quer dizer Loja\Produto.
<?php
require __DIR__ . '/src/Loja/Produto.php';
require __DIR__ . '/src/Loja/funcoes.php';
require __DIR__ . '/src/Blog/Produto.php';
use Loja\Produto;
use Blog\Produto as Post;
use function Loja\formatar_preco;
use const Loja\MOEDA;
$caneca = new Produto("Caneca", 19.9);
$post = new Post("Review da caneca");
echo $caneca->nome, ": ", formatar_preco($caneca->preco), "\n";
echo $post->titulo, "\n";
echo get_class($caneca), " e ", get_class($post), "\n";
echo "Moeda: ", MOEDA, "\n";
O arquivo src/Loja/funcoes.php tem uma constante e uma função no namespace Loja:
<?php
namespace Loja;
const MOEDA = "R$";
function formatar_preco(float $valor): string
{
return MOEDA . " " . number_format($valor, 2, ",", ".");
}
- use Loja\Produto;
- Neste arquivo,
ProdutosignificaLoja\Produto. O nome nouseé sempre lido como totalmente qualificado: a barra da frente é opcional (use \Loja\Produto;funciona igual, mas ninguém escreve). - use Blog\Produto as Post;
- Importa com um apelido (
as= "como").PostsignificaBlog\Produto. É assim que as duas classesProdutoconvivem no mesmo arquivo. - use function Loja\formatar_preco;
- Importa uma função. Sem a palavra
function, ouseimporta só classes (e interfaces, traits, enums). - use const Loja\MOEDA;
- Importa uma constante.
- get_class($caneca)
- Mostra o nome completo da classe do objeto.
$ php index.php Caneca: R$ 19,90 Review da caneca Loja\Produto e Blog\Produto « duas classes diferentes, sem conflito Moeda: R$
use não carrega arquivo nenhum
É o erro de entendimento mais comum. O use só cria um atalho de nome; quem carrega o código ainda é o require. Se você tirar os require do exemplo, o PHP vai dizer que a classe não existe. Na próxima aula, o autoload faz o PHP carregar os arquivos sozinho, e aí sim os require somem.
Onde o use vale
- O
usefica no topo do arquivo, logo depois donamespace(se houver), fora de funções e classes. - Ele vale só para aquele arquivo. Um
usenoindex.phpnão vale dentro de um arquivo incluído por ele: cada arquivo faz os seus. - Ele só afeta os nomes que você escreve no código. Nomes dentro de textos (por exemplo,
new $nomeDaClassecom$nomeDaClasse = "Produto") são sempre lidos como nome completo, sem olhar osuse.
Agrupando vários use
Quando você importa várias coisas do mesmo namespace, pode agrupar com chaves:
<?php
use Loja\{Produto, Carrinho, Pedido};
// é o mesmo que:
// use Loja\Produto;
// use Loja\Carrinho;
// use Loja\Pedido;
use Blog\{Produto as Post, Comentario};
As duas formas são equivalentes. Muitos projetos preferem um use por linha, porque fica mais fácil ver, numa comparação de versões, o que foi acrescentado ou removido.
Missão: o index.php já usa a classe Produto da loja. Importe também a classe Produto do arquivo blog.php com o apelido Post e descomente as duas últimas linhas. A saída deve mostrar Blog\Produto. (Tente primeiro use Blog\Produto;, sem apelido, para ver o erro.)
<?php
require 'loja.php';
require 'blog.php';
use Loja\Produto;
$caneca = new Produto("Caneca");
echo get_class($caneca), ": ", $caneca->nome, "\n";
// $post = new Post("Review da caneca");
// echo get_class($post), ": ", $post->titulo, "\n";
<?php
namespace Loja;
class Produto
{
public function __construct(public string $nome) {}
}
<?php
namespace Blog;
class Produto
{
public function __construct(public string $titulo) {}
}
<?php
require 'loja.php';
require 'blog.php';
use Loja\Produto;
use Blog\Produto as Post;
$caneca = new Produto("Caneca");
echo get_class($caneca), ": ", $caneca->nome, "\n";
$post = new Post("Review da caneca");
echo get_class($post), ": ", $post->titulo, "\n";
Funções globais: strlen e \strlen
As funções e classes que vêm com o PHP (strlen, count, DateTime, Exception…) moram no namespace global, o de nome vazio. O nome completo de strlen é \strlen. O que acontece quando você as usa dentro do seu namespace?
<?php
namespace Loja;
echo strlen("Caneca"), "\n";
echo \strlen("Caneca"), "\n";
$hoje = new DateTime("2026-10-16");
echo $hoje->format("d/m/Y"), "\n";
$ php n3.php
6
6
Fatal error: Uncaught Error: Class "Loja\DateTime" not found in /home/ana/ns/n3.php:6
Stack trace:
#0 {main}
thrown in /home/ana/ns/n3.php on line 6
As funções funcionaram; a classe, não. A diferença é uma regra do PHP chamada recuo para o global (fallback):
Você escreve, dentro de namespace Loja | O PHP procura |
|---|---|
Uma função não qualificada: strlen(…) | Primeiro Loja\strlen; se não existir, recua para a global \strlen |
Uma constante não qualificada: PHP_EOL | Primeiro Loja\PHP_EOL; se não existir, recua para \PHP_EOL |
Uma classe não qualificada: new DateTime | Só Loja\DateTime. Classes não recuam |
Por isso, dentro de um namespace, toda classe do PHP precisa da barra na frente ou de um use:
<?php
namespace Loja;
$hoje = new \DateTime("2026-10-16");
echo $hoje->format("d/m/Y"), "\n";
$ php n4.php 16/10/2026
Ou, com use no topo: use DateTime; e depois new DateTime(…). O mesmo vale para \Exception, \PDO, \InvalidArgumentException, \ArrayObject… Esse é o erro número 1 de quem começa a usar namespaces, principalmente em catch (Exception $e), que dentro de um namespace procura Loja\Exception (e, como essa classe não existe, o catch simplesmente não pega nada).
\strlen() com barra?
Não é obrigatório: o recuo encontra a função. Mas com a barra o PHP não precisa "tentar Loja\strlen primeiro", e o OPcache (o otimizador que vem com o PHP) consegue trocar algumas funções, como \strlen e \count, por instruções mais rápidas. A diferença é pequena; o mais importante é seguir o estilo do projeto. Ferramentas de estilo (veja Padrões PSR) podem colocar as barras automaticamente.
Um namespace por arquivo
O PHP permite declarar vários namespaces no mesmo arquivo (com chaves: namespace Loja { … } e namespace Blog { … }), mas ninguém faz isso em projetos de verdade. A regra prática, seguida por todo o ecossistema PHP, é:
- Um arquivo, um namespace, declarado logo no começo.
- Uma classe por arquivo, e o arquivo tem o nome da classe:
Produto.phpcontémclass Produto. - As pastas imitam o namespace:
Loja\Pagamento\Pixfica emsrc/Loja/Pagamento/Pix.php.
A regra 3 parece só capricho, mas é o que permite ao PHP descobrir sozinho em qual arquivo está cada classe. Essa é a próxima aula: Autoload e PSR-4.
O namespace tem que vir primeiro
Antes da linha namespace só pode haver o <?php, comentários e o declare(strict_types=1);. Qualquer outra coisa dá erro:
<?php echo "Olá\n"; namespace Loja;
$ php n2.php
Fatal error: Namespace declaration statement has to be the very first statement or after any declare call in the script in /home/ana/ns/n2.php on line 3
Stack trace:
#0 {main}
Tradução: "a declaração de namespace precisa ser a primeiríssima instrução do script, ou vir logo depois de um declare". O começo padrão de um arquivo moderno fica assim:
<?php
declare(strict_types=1);
namespace Loja;
use DateTimeImmutable;
use Loja\Pagamento\Pix;
class Carrinho
{
// ...
}
A ordem é sempre: <?php → declare → namespace → use → o código. (O declare(strict_types=1) é explicado em Tipos Avançados.) Atenção também a espaços ou linhas em branco antes do <?php: eles contam como saída de HTML e também disparam o erro.
Formas de se referir a uma classe: qual usar
| Forma | Exemplo | Quando usar |
|---|---|---|
use no topo + nome curto | use Loja\Produto; … new Produto | O padrão. Deixa claro, no topo, de quais classes o arquivo depende. |
use … as | use Blog\Produto as Post; | Dois nomes iguais no mesmo arquivo, ou um nome muito genérico. |
| Totalmente qualificado | new \Loja\Produto, new \DateTime | Uso único e rápido; classes do PHP dentro de um namespace (se você não quiser um use). |
| Qualificado (relativo) | new Pagamento\Pix dentro de namespace Loja | Raramente. Funciona, mas confunde; prefira use. |
| Nome como texto | $c = "Loja\\Produto"; new $c(…) | Nome decidido em tempo de execução. Sempre o nome completo, sem a barra da frente; dentro de aspas duplas, a barra precisa ser dobrada (ou use Produto::class). |
Quando dá errado
use)
<?php
require __DIR__ . '/src/Loja/Produto.php';
$caneca = new Produto("Caneca", 19.9);
$ php sem-use.php
Fatal error: Uncaught Error: Class "Produto" not found in /home/ana/ns2/sem-use.php:4
Stack trace:
#0 {main}
thrown in /home/ana/ns2/sem-use.php on line 4
O que significa: o arquivo foi carregado, mas a classe se chama Loja\Produto, e o PHP procurou Produto no namespace global. Leia o nome entre aspas na mensagem: ele mostra exatamente o nome completo que o PHP procurou.
Como consertar: use Loja\Produto; no topo, ou new \Loja\Produto(…).
O que significa: dentro de namespace Loja, você usou uma classe do próprio PHP sem barra. Classes não recuam para o global (veja a seção sobre strlen, acima).
Como consertar: new \DateTime(…) ou use DateTime; no topo.
catch não pegou a exceção
<?php
namespace Loja;
try {
throw new \Exception("Deu ruim");
} catch (Exception $e) {
echo "peguei\n";
}
echo "fim\n";
$ php catch.php
Fatal error: Uncaught Exception: Deu ruim in /home/ana/ns3/catch.php:5
Stack trace:
#0 {main}
thrown in /home/ana/ns3/catch.php on line 5
O que significa: o catch (Exception $e), dentro de namespace Loja, espera uma Loja\Exception. Essa classe não existe, mas o PHP não reclama disso no catch: ele só não pega nada, e a exceção escapa ("Uncaught" = não capturada). Nem o peguei nem o fim apareceram.
Como consertar: catch (\Exception $e) ou use Exception; no topo. Veja Exceções.
O que significa: você escreveu Loja\Produto (sem barra na frente) dentro de namespace App, e o PHP o leu como App\Loja\Produto. O nome na mensagem entrega o problema: tem um pedaço a mais na frente.
Como consertar: use Loja\Produto; ou \Loja\Produto.
<?php require __DIR__ . '/src/Loja/Produto.php'; require __DIR__ . '/src/Blog/Produto.php'; use Loja\Produto; use Blog\Produto;
$ php dois-use.php
Fatal error: Cannot use Blog\Produto as Produto because the name is already in use in /home/ana/ns2/dois-use.php on line 6
Stack trace:
#0 {main}
O que significa: "não é possível usar Blog\Produto como Produto, porque esse nome já está em uso". Os dois use tentaram criar o mesmo atalho. Repare que o erro aparece antes de qualquer linha rodar: é um erro de compilação.
Como consertar: dê um apelido a um deles: use Blog\Produto as Post;.
$ php funcao-sem-use.php
Fatal error: Uncaught Error: Call to undefined function formatar_preco() in /home/ana/ns2/funcao-sem-use.php:4
Stack trace:
#0 {main}
thrown in /home/ana/ns2/funcao-sem-use.php on line 4
O que significa: a função está em Loja\formatar_preco, e o arquivo (no namespace global) chamou só formatar_preco. Um use Loja\Produto não serviria: use sem function não importa funções.
Como consertar: use function Loja\formatar_preco; ou \Loja\formatar_preco(10).
O que significa: há código, HTML ou até um espaço/linha em branco antes do <?php ou entre ele e o namespace. (Arquivos salvos com "UTF-8 com BOM", uma marca invisível no começo do arquivo, também causam isso.)
Como consertar: deixe só <?php, comentários e declare(…) antes do namespace. No editor, salve como "UTF-8" (sem BOM).
Referência
| Escrita | O que faz |
|---|---|
namespace Loja; | Coloca o resto do arquivo no namespace Loja |
namespace Loja\Pagamento; | Namespace com vários níveis |
use Loja\Produto; | Atalho: Produto = Loja\Produto |
use Blog\Produto as Post; | Atalho com apelido |
use Loja\{Produto, Carrinho}; | Vários atalhos do mesmo namespace |
use function Loja\formatar_preco; | Atalho para uma função |
use const Loja\MOEDA; | Atalho para uma constante |
\Loja\Produto | Nome totalmente qualificado (absoluto) |
\strlen(), \DateTime | Função/classe do namespace global |
Produto::class | O nome completo, como texto: "Loja\Produto" |
__NAMESPACE__ | O namespace atual, como texto |
namespace\funcao() | "Do namespace atual", escrito de forma explícita (raro) |
Exercícios
1. Declarar o namespace
Complete a primeira linha de código para a classe Aluno se chamar Escola\Aluno:
class Aluno {}
2. Importar com apelido
Complete para que, neste arquivo, Post signifique Blog\Produto:
3. A classe do PHP dentro do namespace
O arquivo começa com namespace Loja;. Complete para criar uma exceção do próprio PHP sem nenhum use:
4. Dentro de namespace Loja;, você chama count($itens). O que acontece, se não existir Loja\count?
5. Num arquivo com namespace App;, você escreve new Loja\Produto(). Qual classe o PHP procura?
6. O que o use Loja\Produto; faz?
Missão final: o arquivo escola.php tem a função media() sem namespace. (1) Coloque-a no namespace Escola. (2) No index.php, importe-a com use function Escola\media;. A saída deve ser Média: 7.5. Rode depois do passo 1 e antes do passo 2 para ver o erro Call to undefined function media().
<?php require 'escola.php'; echo "Média: ", media([7, 8, 6.5, 8.5]), "\n";
<?php
function media(array $notas): float
{
return array_sum($notas) / count($notas);
}
<?php require 'escola.php'; use function Escola\media; echo "Média: ", media([7, 8, 6.5, 8.5]), "\n";
<?php
namespace Escola;
function media(array $notas): float
{
return array_sum($notas) / count($notas);
}
Resumo
- Namespace é o "sobrenome" de classes, funções e constantes:
Loja\ProdutoeBlog\Produtoconvivem sem conflito. namespace Loja;vem logo no começo do arquivo (sódeclaree comentários podem vir antes).- Nome com
\na frente é absoluto; sem barra na frente, é relativo ao namespace atual. usecria atalhos (só de nome, não carrega arquivo);asdá apelido;use functioneuse constpara funções e constantes.- Funções e constantes do PHP recuam para o global (
strlenfunciona); classes não: use\DateTime,\Exceptionou umuse. - Um namespace por arquivo, uma classe por arquivo, pastas iguais ao namespace: isso prepara o autoload.