Namespaces são um recurso fundamental do PHP moderno para organizar o código e evitar conflitos de nomes entre classes, funções e constantes. Imagine que você está construindo um sistema grande com várias bibliotecas: sem namespaces, duas classes chamadas Usuario de módulos diferentes colidiriam. Com namespaces, cada uma vive em seu próprio espaço, como diretórios em um sistema de arquivos. Nesta aula, você vai dominar a declaração de namespaces, a importação com use, a criação de aliases e as melhores práticas para estruturar projetos de forma limpa e escalável.

Vamos começar com o básico: o que é um namespace e como declará-lo. Em seguida, veremos como importar classes e outros símbolos com use, como criar apelidos (aliases) para simplificar referências, e finalmente como organizar arquivos e pastas seguindo padrões como PSR-4. Ao final, você terá uma base sólida para aplicar namespaces em qualquer projeto PHP.

namespace

A declaração de um namespace é a primeira instrução de um arquivo PHP (após <?php) e define um escopo para todos os elementos declarados no arquivo: classes, interfaces, funções e constantes. A sintaxe é simples: namespace Nome\Namespace;. O nome pode incluir subnamespaces separados por barra invertida, criando uma hierarquia, como App\Models ou MinhaEmpresa\Biblioteca\Util.

Um arquivo pode ter apenas um namespace, mas você pode usar chaves para declarar múltiplos namespaces em um mesmo arquivo (embora isso seja raro e desencorajado). A regra prática é: um arquivo = um namespace, e o namespace deve refletir a estrutura de diretórios do projeto, seguindo a PSR-4. Por exemplo, se você tem uma classe Usuario na pasta src/Models, o namespace seria App\Models.

<?php
// Arquivo: src/Models/Usuario.php
namespace App\Models;

class Usuario {
    public function __construct(private string $nome) {}

    public function getNome(): string {
        return $this->nome;
    }
}

Para usar essa classe em outro arquivo, você precisa se referir ao nome completo (FQN - Fully Qualified Name) ou importá-la. O FQN é o namespace + nome da classe, como App\Models\Usuario. Sem importação, você teria que escrever isso toda vez, o que é trabalhoso. Por isso, usamos use.

Também é possível declarar funções e constantes em namespaces. Elas seguem as mesmas regras de nomenclatura e resolução. Por exemplo:

<?php
namespace App\Helpers;

function formatarData(DateTime $data): string {
    return $data->format('d/m/Y');
}

const VERSAO = '1.0.0';

Para acessar essas funções e constantes, você usa o namespace: App\Helpers\formatarData(...) ou App\Helpers\VERSAO.

use

A declaração use importa um namespace ou um símbolo específico para o escopo atual, permitindo que você o referencie pelo nome curto. Ela deve estar no nível superior do arquivo (não dentro de funções ou classes) e pode importar classes, interfaces, funções e constantes. A sintaxe básica é use Nome\Completo\Classe;. Depois disso, você pode usar apenas Classe no resto do arquivo.

É importante notar que use não carrega o arquivo; ele apenas cria um alias. O autoload (como o Composer) é responsável por carregar a classe quando ela é instanciada. Vamos ver um exemplo prático:

<?php
// Arquivo: public/index.php
use App\Models\Usuario;
use App\Helpers\formatarData;

$usuario = new Usuario('Maria');
$data = new DateTime('2025-01-01');
echo formatarData($data); // 01/01/2025

Você também pode importar múltiplos símbolos em uma única linha com vírgulas, embora seja mais legível separar por linha. Exemplo:

use App\Models\{Usuario, Pedido};
use App\Services\Pagamento as PagamentoService;

Além disso, o PHP permite importar funções e constantes com use function e use const respectivamente. Isso evita ambiguidades e deixa claro o que está sendo importado.

<?php
use function App\Helpers\formatarData;
use const App\Helpers\VERSAO;

echo formatarData(new DateTime());
echo VERSAO;

Uma observação importante: o use não afeta a resolução de nomes em tempo de execução; ele é apenas um mecanismo de compilação. Portanto, se você importar uma classe e depois usar um nome igual a outro importado, pode haver conflito. Nesse caso, você pode usar aliases (próximo tópico) para resolver.

Aliases

Aliases permitem criar um apelido para um nome totalmente qualificado, tornando o código mais conciso e evitando colisões de nomes. A sintaxe é use Nome\Completo\Classe as Apelido;. O alias pode ser usado para classes, interfaces, funções e constantes.

Por exemplo, se você tem duas classes Usuario de namespaces diferentes, pode importá-las com aliases:

<?php
use App\Models\Usuario as UsuarioModel;
use App\Auth\Usuario as UsuarioAuth;

$model = new UsuarioModel();
$auth = new UsuarioAuth();

Isso é essencial em projetos que integram múltiplas bibliotecas com nomes de classes semelhantes. Outro uso comum é encurtar nomes longos de classes, como use Symfony\Component\HttpFoundation\Response as Response; para evitar escrever o FQN toda vez.

Lembre-se de que o alias é válido apenas no arquivo onde o use é declarado. Cada arquivo precisa de seus próprios imports. Isso pode parecer redundante, mas mantém a independência e clareza.

Para funções e constantes, a sintaxe é semelhante:

use function App\Helpers\formatarData as fd;
use const App\Helpers\VERSAO as VER;

Depois, você pode chamar fd($data) e usar VER.

Organização de código

Namespaces são a base para uma organização eficiente de código em PHP. A prática recomendada é espelhar a estrutura de namespaces na estrutura de diretórios do projeto. O padrão PSR-4, adotado pelo Composer, define que cada namespace raiz tem um diretório base, e subnamespaces correspondem a subdiretórios. Por exemplo, se o namespace raiz é App e o diretório base é src/, então a classe App\Models\Usuario deve estar em src/Models/Usuario.php.

Isso facilita o autoload: o Composer registra um autoloader que converte o FQN da classe em um caminho de arquivo. Para configurar, no composer.json, você define:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

Depois, execute composer dump-autoload para atualizar o autoloader. A partir daí, qualquer classe em src/ com namespace App\... será carregada automaticamente quando usada.

Ao organizar, é comum ter pastas como src/Models, src/Controllers, src/Services, etc. Cada uma com seu namespace correspondente. Isso mantém o projeto modular, testável e fácil de navegar.

Além disso, é uma boa prática usar nomes de namespace em PascalCase (ex.: MeuProjeto) e evitar palavras reservadas. A hierarquia deve refletir a lógica do domínio, não a estrutura técnica (ex.: App\Models em vez de App\Database\Tables).

Outra dica: evite usar o mesmo nome de classe em namespaces diferentes sem alias, pois isso pode causar confusão. Prefira sempre importar com use e, se necessário, criar aliases significativos.

Boas práticas

Além da organização, algumas boas práticas ajudam a evitar erros comuns. Sempre declare o namespace no início do arquivo, após <?php e antes de qualquer outro código. Use um namespace por arquivo. Não misture declarações de namespace com código de execução no mesmo arquivo. Prefira um estilo consistente: todos os imports no topo, ordenados alfabeticamente ou por tipo (classes, funções, constantes).

Outra prática é usar aliases apenas quando necessário, para não poluir o código com apelidos desnecessários. E lembre-se de que namespaces são case-insensitive, mas por convenção usamos PascalCase para namespaces e classes, camelCase para funções e métodos.

Por fim, teste sempre o autoload após adicionar novos arquivos. O Composer é seu aliado nesse processo, mas é preciso configurá-lo corretamente.

Referências

Exercícios

  1. Crie um arquivo src/Models/Produto.php com o namespace App\Models e uma classe Produto com uma propriedade nome e um método getNome().

    ✓ Resposta:
    <?php
    namespace App\Models;
    
    class Produto {
        public function __construct(private string $nome) {}
    
        public function getNome(): string {
            return $this->nome;
        }
    }
    
  2. Em um arquivo public/teste.php, importe a classe App\Models\Produto com use e instancie um objeto chamando getNome().

    ✓ Resposta:
    <?php
    require __DIR__ . '/../vendor/autoload.php';
    
    use App\Models\Produto;
    
    $produto = new Produto('Notebook');
    echo $produto->getNome(); // Notebook
    
  3. Defina duas classes com o mesmo nome Logger em namespaces diferentes: App\Loggers\Logger e App\Helpers\Logger. Em um arquivo, importe ambas usando aliases LoggerLog e LoggerHelp e instancie cada uma.

    ✓ Resposta:
    <?php
    use App\Loggers\Logger as LoggerLog;
    use App\Helpers\Logger as LoggerHelp;
    
    $log = new LoggerLog();
    $help = new LoggerHelp();
    
  4. Crie uma função somar no namespace App\Matematica e importe-a com use function em outro arquivo, chamando-a.

    ✓ Resposta:
    // Arquivo: src/Matematica.php
    namespace App\Matematica;
    
    function somar(int $a, int $b): int {
        return $a + $b;
    }
    
    // Arquivo: public/index.php
    use function App\Matematica\somar;
    
    echo somar(2, 3); // 5
    
  5. Configure o composer.json para autoload PSR-4 com namespace raiz App apontando para a pasta src/ e explique o que acontece quando você instancia uma classe.

    ✓ Resposta:
    {
        "autoload": {
            "psr-4": {
                "App\\": "src/"
            }
        }
    }
    

    Quando você instancia new App\Models\Produto(), o autoloader do Composer converte o FQN em src/Models/Produto.php e inclui o arquivo se a classe não existir ainda.