Padrões de Projeto em PHP: não são apenas palavras da moda, mas sua ferramenta para código limpo
\n\nTodo desenvolvedor PHP, mais cedo ou mais tarde, se depara com uma situação em que o código vira um "espaguete": classes inchadas, dependências confusas e adicionar uma nova funcionalidade exige reescrever metade do projeto. Parece familiar?
\nÉ exatamente aqui que os padrões de projeto em PHP (design patterns) entram em cena — soluções arquiteturais testadas pelo tempo para problemas recorrentes. Eles não são bibliotecas prontas ou pedaços de código para copiar e colar. São conceitos que ajudam a organizar a estrutura da sua aplicação para que ela seja flexível, testável e fácil de manter.
\nNeste artigo, não vamos abordar teoria pela teoria. Vamos analisar exemplos reais de código PHP e responder à pergunta principal: "Quando esse padrão é realmente necessário e quando ele só vai complicar a vida?"
\n\nPor que usar padrões de projeto em PHP?
\nMuitos desenvolvedores iniciantes acham os padrões uma abstração desnecessária. Mas, na prática, eles resolvem três problemas-chave:
\n- \n
- Baixo acoplamento (loose coupling) — as classes dependem menos umas das outras, facilitando a substituição e os testes. \n
- Maior reutilização — você não escreve o mesmo código em lugares diferentes. \n
- Refatoração simplificada — quando os requisitos mudam (e eles sempre mudam), o padrão permite fazer alterações localmente sem quebrar todo o sistema. \n
Mas tem um detalhe: os padrões devem ser aplicados com consciência. Se você tem uma aplicação CRUD simples com 3 tabelas, implementar uma fábrica complexa ou um builder abstrato é overengineering. O padrão se justifica quando você prevê um aumento de complexidade ou quando a arquitetura atual já está começando a "doer".
\n\nTop 5 padrões de projeto em PHP com exemplos
\n\n1. Singleton — quando o objeto deve ser único
\nQuando usar: Você precisa de uma única instância de uma classe para toda a aplicação. O exemplo clássico é a conexão com o banco de dados ou um logger. Se você criar uma nova conexão em cada controller, corre o risco de estourar o limite de conexões.
\nclass Database {\n private static ?Database $instance = null;\n private PDO $connection;\n\n private function __construct() {\n $this->connection = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');\n }\n\n // Impede clonagem e unserialize\n private function __clone() {}\n public function __wakeup() {\n throw new \\Exception("Cannot unserialize singleton");\n }\n\n public static function getInstance(): Database {\n if (self::$instance === null) {\n self::$instance = new self();\n }\n return self::$instance;\n }\n\n public function getConnection(): PDO {\n return $this->connection;\n }\n}\n\n// Uso\n$db = Database::getInstance();\n$pdo = $db->getConnection();\nImportante: O Singleton é frequentemente criticado por criar um estado global. Em frameworks modernos (Laravel, Symfony), ele é substituído pelo contêiner de Injeção de Dependência (Dependency Injection). Use Singleton apenas em projetos simples sem DI.
\n\n2. Factory Method — quando a criação do objeto é complexa
\nQuando usar: Você não sabe de antemão qual classe exata precisa ser criada, ou o processo de inicialização do objeto requer várias etapas. Por exemplo, criar diferentes tipos de notificações (Email, SMS, Push).
\ninterface Notification {\n public function send(string $message): void;\n}\n\nclass EmailNotification implements Notification {\n public function send(string $message): void {\n echo "Enviando Email: $message\\n";\n }\n}\n\nclass SMSNotification implements Notification {\n public function send(string $message): void {\n echo "Enviando SMS: $message\\n";\n }\n}