Como organizar um projeto PHP: Arquitetura Hexagonal sem dor

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Quando seu monolito PHP começa a rachar

\n

Você já se viu em uma situação em que trocar o banco de dados de MySQL para PostgreSQL se transformou em uma missão de uma semana? Ou quando precisou adicionar um novo cliente de API, mas o código estava tão entrelaçado com o framework que era mais fácil reescrever tudo do zero? Familiar?

\n

A maioria dos desenvolvedores PHP, mais cedo ou mais tarde, enfrenta o "macarrão" em controllers e models. Frameworks como Laravel ou Symfony oferecem ferramentas convenientes, mas também impõem um forte acoplamento a eles. Existe uma saída — a Arquitetura Hexagonal (também conhecida como "portas e adaptadores" ou arquitetura hexagonal).

\n

Neste artigo, vamos analisar como construir uma aplicação em PHP que não depende de framework, banco de dados ou serviços externos. Você verá exemplos de código que podem ser aplicados imediatamente no seu projeto. Vamos lá!

\n\n

O que é Arquitetura Hexagonal e por que você precisa dela?

\n

Imagine um hexágono. No centro — sua lógica de negócios (domínio). Ao redor — as "portas" (interfaces), através das quais o mundo externo se comunica com o núcleo. E do lado de fora — os "adaptadores", que implementam essas portas: controllers, repositórios, clientes de API.

\n

A ideia principal: o núcleo da aplicação não sabe nada sobre o mundo externo. Ele não importa o Laravel, não conhece PDO e não chama curl. Toda a dependência é direcionada para dentro — os adaptadores dependem das portas, e não o contrário.

\n

As vantagens dessa abordagem são óbvias:

\n
    \n
  • Testabilidade: a lógica de negócios pode ser testada sem banco de dados e requisições HTTP.
  • \n
  • Flexibilidade: trocar de BD, fila ou framework é simplesmente escrever um novo adaptador.
  • \n
  • Limpeza do código: você não mistura "o que fazer" com "como fazer".
  • \n
\n

Parece mágica? Vamos ver o código.

\n\n

Estrutura do projeto: esqueleto básico

\n

Para o exemplo, vamos usar um cenário simples: registro de usuário. Precisamos salvar o usuário no BD e enviar um e-mail de boas-vindas.

\n

Assim será a estrutura típica de diretórios:

\n
src/\n├── Domain/\n│   ├── Entity/\n│   │   └── User.php\n│   ├── Repository/\n│   │   └── UserRepositoryInterface.php\n│   ├── Service/\n│   │   └── UserRegistrationService.php\n│   └── Event/\n│       └── UserRegisteredEvent.php\n├── Infrastructure/\n│   ├── Persistence/\n│   │   └── DoctrineUserRepository.php\n│   ├── Mail/\n│   │   └── SymfonyMailerAdapter.php\n│   └── Controller/\n│       └── RegisterUserController.php\n└── Application/\n    └── UseCase/\n        └── RegisterUserUseCase.php
\n

Observe: Domain é a lógica de negócios pura. Infrastructure são os adaptadores. Application são os casos de uso (use cases).

\n\n

Passo 1: O núcleo — domínio e portas

\n

Entidade (Entity)

\n

Vamos começar pelo mais simples — o usuário. É apenas uma classe com dados, sem dependências.

\n
<?php\nnamespace App\\Domain\\Entity;\n\nclass User\n{\n    public function __construct(\n        private readonly string $id,\n        private string $name,\n        private string $email\n    ) {}\n\n    public function getId(): string\n    {\n        return $this->id;\n    }\n\n    public function getName(): string\n    {\n        return $this->name;\n    }\n\n    public function getEmail(): string\n    {\n        return $this->email;\n    }\n}
\n\n

Porta — interface do repositório

\n

Agora definimos como vamos salvar o usuário. Esta é uma porta — uma interface que será implementada pelo adaptador.

\n
<?php\nnamespace App\\Domain\\Repository;\n\nuse App\\Domain\\Entity\\User;\n\ninterface UserRepositoryInterface\n{\n    public function save(User $user): void;\n    public function findByEmail(string $email): ?User;\n}
\n\n

Porta — interface do serviço de e-mail

\n

De forma análoga para o envio de e-mails:

\n
<?php\nnamespace App\\Domain\\Service;\n\nuse App\\                

Blogs

Book Recommendations