Princípios SOLID em PHP: teoria e prática
SOLID — são cinco princípios fundamentais da programação orientada a objetos, formulados por Robert Martin. Eles ajudam a criar código flexível, sustentável e escalável. Neste artigo, analisaremos cada princípio com exemplos em PHP, desde conceitos simples até cenários práticos reais.
1. Single Responsibility Principle (SRP) — Princípio da Responsabilidade Única
Formulação: Uma classe deve ter apenas um motivo para mudar. Em outras palavras, cada classe é responsável por apenas uma tarefa ou funcionalidade.
A violação do SRP frequentemente leva a "objetos divinos" que sabem e fazem demais. Vamos considerar um exemplo ruim:
class Report { public function generate($data) { // Geração do relatório return "Relatório: " . json_encode($data); }
public function saveToFile($filename, $content) { file_put_contents($filename, $content); }
public function sendEmail($to, $subject, $body) { mail($to, $subject, $body); }}Aqui a classe Report é responsável pela geração, salvamento e envio — três responsabilidades diferentes. Vamos corrigir isso:
class ReportGenerator { public function generate($data) { return "Relatório: " . json_encode($data); }}
class FileSaver { public function save($filename, $content) { file_put_contents($filename, $content); }}
class EmailSender { public function send($to, $subject, $body) { mail($to, $subject, $body); }}
// Uso$report = new ReportGenerator();$content = $report->generate($data);
$saver = new FileSaver();$saver->save('report.txt', $content);
$sender = new EmailSender();$sender->send('admin@example.com', 'Relatório pronto', $content);Dica prática: Se você vir no nome da classe a conjunção "e" (por exemplo, UserAndLogger), é um sinal claro de violação do SRP.
2. Open-Closed Principle (OCP) — Princípio Aberto/Fechado
Formulação: As classes devem estar abertas para extensão, mas fechadas para modificação. Você deve ser capaz de adicionar novas funcionalidades sem alterar o código existente.
A violação do OCP ocorre quando adicionar um novo tipo exige alterar classes existentes. Exemplo de código ruim:
class PaymentProcessor { public function process($type, $amount) { if ($type === 'credit_card') { // Processamento de cartão de crédito } elseif ($type === 'paypal') { // Processamento do PayPal } elseif ($type === 'crypto') { // Processamento de criptomoeda } // Adicionar um novo tipo = alterar esta classe }}Solução — usar polimorfismo através de interfaces:
interface PaymentMethod { public function process($amount);}
class CreditCardPayment implements PaymentMethod { public function process($amount) { echo "Processamento de cartão de crédito no valor de $amount"; }}
class PayPalPayment implements PaymentMethod { public function process($amount) { echo "Processamento do PayPal no valor de $amount"; }}
class PaymentProcessor { public function process(PaymentMethod $method, $amount) { $method->process($amount); }}
// Uso$processor = new PaymentProcessor();$processor->process(new CreditCardPayment(), 100);$processor->process(new PayPalPayment(), 200);Agora, adicionar um novo método de pagamento (por exemplo, ApplePayPayment) não exige alterar PaymentProcessor.
3. Liskov Substitution Principle (LSP) — Princípio da Substituição de Liskov
Formulação: Os objetos das subclasses devem ser intercambiáveis com os objetos da classe base