Injeção de Dependência em PHP: guia completo com exemplos de código

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

Injeção de Dependência em PHP: na prática



Injeção de Dependência (DI) — um dos princípios-chave do SOLID, que permite escrever código flexível, testável e de fácil manutenção. Neste artigo, vamos analisar como implementar a injeção de dependências em PHP com exemplos reais, sem teorias abstratas. Você aprenderá como eliminar acoplamentos rígidos entre classes e tornar seu código preparado para mudanças.



O que é Injeção de Dependência e para que serve?



Imagine que você tem uma classe UserController que trabalha com um banco de dados. Sem DI, você provavelmente cria o objeto de conexão diretamente dentro do controller:



class UserController {    private $db;    public function __construct() {        $this->db = new MySQLConnection('localhost', 'user', 'pass');    }}


Essa abordagem cria um acoplamento rígido (tight coupling). Se você quiser mudar para PostgreSQL ou usar um objeto mock para testes, terá que alterar o código do controller. A Injeção de Dependência resolve esse problema: as dependências são passadas de fora, e não criadas dentro da classe.



Principais vantagens da DI:

  • Redução do acoplamento do código
  • Facilidade de teste (substituição simples de dependências)
  • Reutilização de classes
  • Arquitetura limpa e cumprimento do princípio da inversão de dependências (DIP)


Formas de injeção de dependências em PHP



Existem três formas principais de injeção de dependências. Vamos analisar cada uma com exemplos.



1. Injeção via construtor



A forma mais comum e recomendada. As dependências são passadas através dos parâmetros do construtor e armazenadas nas propriedades da classe.



<?phpinterface DatabaseInterface {    public function query(string $sql): array;}

class MySQLDatabase implements DatabaseInterface { public function query(string $sql): array { // Lógica real de trabalho com MySQL return ['id' => 1, 'name' => 'John']; }}

class UserRepository { private DatabaseInterface $db; public function __construct(DatabaseInterface $db) { $this->db = $db; } public function getUser(int $id): array { return $this->db->query("SELECT * FROM users WHERE id = $id"); }}

// Uso:$db = new MySQLDatabase();$repo = new UserRepository($db);$user = $repo->getUser(1);?>


Observe: usamos a interface DatabaseInterface. Isso permite substituir facilmente a implementação — por exemplo, por um mock de teste.



2. Injeção via setters



Usada quando a dependência não é obrigatória no momento da criação do objeto ou pode mudar durante a execução.



<?phpclass MailService {    private ?MailerInterface $mailer = null;        public function setMailer(MailerInterface $mailer): void {        $this->mailer = $mailer;    }        public function send(string $to, string $subject, string $body): void {        if ($this->mailer === null) {            throw new \\RuntimeException('Mailer not configured');        }        $this->mailer->send($to, $subject, $body);    }}

// Uso:$mailService = new MailService();$mailService->setMailer(new SmtpMailer());$mailService->send('user@example.com', 'Hello', 'Body');?>


A desvantagem dessa abordagem é que você não garante que a dependência será definida antes da chamada do método send(). Por isso, para dependências obrigatórias, o construtor é preferível.



3. Injeção via método



A dependência é passada diretamente no método onde é necessária. Útil para dependências raras ou contextuais.



<?phpclass ReportGenerator {    public function generate(DataFetcherInterface $fetcher, string $reportType): array {        $data = $fetcher->                

Blogs

Book Recommendations