PHP

Composer e Namespaces Já leu

5 min de leitura

Composer e Namespaces
Antes do Composer, gerenciar dependências em PHP era um pesadelo manual: baixar arquivos, copiá-los para o projeto, atualizar à mão, rezar para que as versões fossem compatíveis. Em 2012, o Composer mudou tudo. Hoje é im

Antes do Composer, gerenciar dependências em PHP era um pesadelo manual: baixar arquivos, copiá-los para o projeto, atualizar à mão, rezar para que as versões fossem compatíveis. Em 2012, o Composer mudou tudo. Hoje é impossível trabalhar profissionalmente com PHP sem ele.

Namespaces, introduzidos no PHP 5.3, resolvem um problema diferente mas relacionado: colisão de nomes. Sem namespaces, duas bibliotecas que definem uma classe Router causam conflito. Com namespaces, Symfony\Component\Routing\Router e League\Route\Router coexistem sem problema.


Namespaces — organizando o código

Um namespace é como um pacote ou diretório lógico para suas classes. Declare no topo do arquivo, antes de qualquer código:

<?php
declare(strict_types=1);

namespace App\Domain\Usuario;

// Esta classe vive em App\Domain\Usuario\Usuario
class Usuario
{
    public function __construct(
        public readonly int    $id,
        public readonly string $nome,
        public readonly string $email,
    ) {}
}
<?php
declare(strict_types=1);

namespace App\Infrastructure\Persistence;

use App\Domain\Usuario\Usuario;                  // importa a classe
use App\Domain\Usuario\UsuarioRepositorioInterface; // importa interface
use PDO;                                           // classe global (sem namespace)

class UsuarioRepositorioPDO implements UsuarioRepositorioInterface
{
    public function __construct(private readonly PDO $pdo) {}

    public function buscarPorId(int $id): ?Usuario
    {
        $stmt = $this->pdo->prepare('SELECT * FROM usuarios WHERE id = ?');
        $stmt->execute([$id]);
        $row = $stmt->fetch();

        if (!$row) return null;

        return new Usuario($row['id'], $row['nome'], $row['email']);
    }
}

Alias — quando dois namespaces têm o mesmo nome de classe:

<?php
use App\Domain\Pedido\Status;
use App\Domain\Pagamento\Status as StatusPagamento; // alias

$status          = new Status('pendente');
$statusPagamento = new StatusPagamento('aguardando');

PSR-4 — Autoloading padronizado

PSR-4 é o padrão que mapeia namespaces para diretórios. Com ele, o PHP sabe onde encontrar cada classe sem que você precise fazer require manualmente:

src/
├── Domain/
│   └── Usuario/
│       ├── Usuario.php                  → App\Domain\Usuario\Usuario
│       └── UsuarioRepositorioInterface.php → App\Domain\Usuario\UsuarioRepositorioInterface
└── Infrastructure/
    └── Persistence/
        └── UsuarioRepositorioPDO.php    → App\Infrastructure\Persistence\UsuarioRepositorioPDO

Composer — gerenciamento de dependências

O arquivo composer.json é o coração de qualquer projeto PHP moderno. Ele define o projeto, suas dependências e o mapeamento PSR-4:

{
    "name": "empresa/meu-projeto",
    "description": "Sistema de gestão de pedidos",
    "type": "project",
    "require": {
        "php": "^8.2",
        "monolog/monolog": "^3.0",
        "vlucas/phpdotenv": "^5.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^11.0",
        "phpstan/phpstan": "^1.10"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "config": {
        "optimize-autoloader": true,
        "sort-packages": true
    }
}

Comandos essenciais:

# Instalar todas as dependências do composer.json
composer install

# Adicionar uma nova dependência
composer require guzzlehttp/guzzle

# Adicionar dependência apenas para desenvolvimento
composer require --dev phpunit/phpunit

# Atualizar todas as dependências para as versões mais recentes permitidas
composer update

# Atualizar apenas uma dependência
composer update monolog/monolog

# Regenerar o autoloader após adicionar classes manualmente
composer dump-autoload

# Verificar se há vulnerabilidades de segurança
composer audit

Versionamento semântico

O Composer usa semver (Semantic Versioning): MAJOR.MINOR.PATCH.

{
    "require": {
        "vendor/pacote": "^2.1.0"
    }
}
Operador Significado Exemplo
^2.1.0 >= 2.1.0 e < 3.0.0 Aceita atualizações minor e patch
~2.1.0 >= 2.1.0 e < 2.2.0 Aceita apenas atualizações patch
2.1.0 Exatamente 2.1.0 Sem flexibilidade
* Qualquer versão Evite em produção
>=2.0 <3.0 Intervalo explícito Equivalente a ^2.0

O composer.lock registra as versões exatas instaladas. Sempre commite o composer.lock em projetos de aplicação — garante que todos os membros da equipe (e o servidor de produção) usem exatamente as mesmas versões. Em bibliotecas, não commite o composer.lock.


Usando as dependências

<?php
declare(strict_types=1);

// O autoloader do Composer — inclua uma única vez no bootstrap da aplicação
require __DIR__ . '/vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Dotenv\Dotenv;

// Carrega variáveis de ambiente do arquivo .env
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

// Cria um logger
$log = new Logger('app');
$log->pushHandler(new StreamHandler(__DIR__ . '/storage/logs/app.log', Logger::DEBUG));

$log->info('Aplicação iniciada', [
    'ambiente' => $_ENV['APP_ENV'] ?? 'production',
    'versao'   => '1.0.0',
]);

// Acessa variável de ambiente definida no .env
$dsn = $_ENV['DATABASE_URL'];

Criando sua própria biblioteca com Composer

{
    "name": "ricardomatosdev/validador",
    "description": "Biblioteca de validação para PHP",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "Ricardo Matos",
            "email": "contato@ricardomatosdev.com"
        }
    ],
    "require": {
        "php": "^8.2"
    },
    "autoload": {
        "psr-4": {
            "RicardoMatos\\Validador\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "RicardoMatos\\Validador\\Tests\\": "tests/"
        }
    }
}

Resumo

Conceito Função
Namespace Agrupa classes em espaços lógicos, evita colisão de nomes
use Importa uma classe para o escopo atual
PSR-4 Mapeia namespaces para diretórios de forma padronizada
Composer Gerencia dependências, autoloading e scripts
composer.lock Garante reprodutibilidade das versões instaladas
^ no semver Permite atualizações compatíveis (minor + patch)

Exercício da semana

  1. Crie um projeto do zero com composer init. Configure o PSR-4 para o namespace MeuProjeto\\ apontando para src/. Crie três classes em subnamespaces diferentes e instancie-as sem nenhum require manual.

  2. Adicione as dependências monolog/monolog e vlucas/phpdotenv. Configure um logger que escreve em arquivo e um arquivo .env com as configurações do banco de dados. Leia as variáveis no código.

  3. Instale phpstan/phpstan como dependência de desenvolvimento. Execute vendor/bin/phpstan analyse src/ --level=5. Corrija todos os erros apontados.

  4. Desafio: publique uma mini biblioteca no GitHub (não precisa ir para o Packagist) com namespace próprio, testes, README e composer.json completo. Instale-a em outro projeto usando o repositório VCS do Composer.


Referências

  • Documentação oficial do Composer: https://getcomposer.org/doc/
  • PSR-4 Autoloading Standard: https://www.php-fig.org/psr/psr-4/
  • Packagist (repositório de pacotes PHP): https://packagist.org/
  • Semantic Versioning: https://semver.org/lang/pt-BR/
Comentários

Mais em PHP

PSR e Padrões de Código
PSR e Padrões de Código

PSR significa PHP Standards Recommendation — recomendações criadas pelo PHP-F...

Design Patterns: Singleton, Factory e Builder
Design Patterns: Singleton, Factory e Builder

Design Patterns (Padrões de Projeto) são soluções codificadas para problemas...

Artigo 41 — Introdução ao Laravel
Artigo 41 — Introdução ao Laravel

Laravel é o framework PHP mais popular do mundo, e por boas razões. Ele não a...