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.

Você vai aprender
  • Por que duas classes com o mesmo nome dão erro, e como o namespace resolve.
  • A declaração namespace e 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), o use … as (apelido), o use function e o use const.
  • Por que strlen funciona dentro de um namespace, mas new DateTime nã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 diaPHP
Sobrenome da famíliaO namespace: Loja
NomeO 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 confundiruse 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 const também: Loja\MOEDA. (Constantes criadas com define() não entram no namespace, a não ser que você escreva o nome completo dentro do define.)
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

TipoExemploComo 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, Produto significa Loja\Produto. O nome no use é 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"). Post significa Blog\Produto. É assim que as duas classes Produto convivem no mesmo arquivo.
use function Loja\formatar_preco;
Importa uma função. Sem a palavra function, o use importa 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$
O 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 use fica no topo do arquivo, logo depois do namespace (se houver), fora de funções e classes.
  • Ele vale só para aquele arquivo. Um use no index.php nã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 $nomeDaClasse com $nomeDaClasse = "Produto") são sempre lidos como nome completo, sem olhar os use.

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 LojaO 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_EOLPrimeiro Loja\PHP_EOL; se não existir, recua para \PHP_EOL
Uma classe não qualificada: new DateTimeSó 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).

Por que alguns projetos escrevem \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, é:

  1. Um arquivo, um namespace, declarado logo no começo.
  2. Uma classe por arquivo, e o arquivo tem o nome da classe: Produto.php contém class Produto.
  3. As pastas imitam o namespace: Loja\Pagamento\Pix fica em src/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

FormaExemploQuando usar
use no topo + nome curtouse Loja\Produto; … new ProdutoO padrão. Deixa claro, no topo, de quais classes o arquivo depende.
use … asuse Blog\Produto as Post;Dois nomes iguais no mesmo arquivo, ou um nome muito genérico.
Totalmente qualificadonew \Loja\Produto, new \DateTimeUso ú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 LojaRaramente. 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

Class "Produto" not found (esqueceu o 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(…).

Class "Loja\DateTime" not found

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.

O 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.

Class "App\Loja\Produto" not found (nome qualificado lido como relativo)

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.

Cannot use … because the name is already in use
<?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;.

Call to undefined function formatar_preco()
$ 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).

Namespace declaration statement has to be the very first statement

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

EscritaO 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\ProdutoNome totalmente qualificado (absoluto)
\strlen(), \DateTimeFunção/classe do namespace global
Produto::classO 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:

<?php

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:

throw new ("Erro");

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\Produto e Blog\Produto convivem sem conflito.
  • namespace Loja; vem logo no começo do arquivo (só declare e comentários podem vir antes).
  • Nome com \ na frente é absoluto; sem barra na frente, é relativo ao namespace atual.
  • use cria atalhos (só de nome, não carrega arquivo); as dá apelido; use function e use const para funções e constantes.
  • Funções e constantes do PHP recuam para o global (strlen funciona); classes não: use \DateTime, \Exception ou um use.
  • Um namespace por arquivo, uma classe por arquivo, pastas iguais ao namespace: isso prepara o autoload.