Introduction : pourquoi SOLID est le fondement d’un code PHP de qualité
Chaque développeur PHP rencontre tôt ou tard une situation où un petit projet se transforme en « code spaghetti ». Les classes deviennent surchargées, les modifications dans une partie du système en cassent une autre, et les tests deviennent un cauchemar. C’est précisément pour résoudre ces problèmes que Robert Martin (Oncle Bob) a formulé les cinq principes SOLID. Ces principes ne sont pas une théorie abstraite, mais des outils pratiques qui aident à créer un code PHP flexible, maintenable et testable.
Dans cet article, nous analyserons chaque principe SOLID : de la théorie aux exemples concrets en PHP 8.x. Vous apprendrez à les appliquer dans le développement quotidien et quels anti-patrons éviter.
1. Single Responsibility Principle (SRP) — Principe de responsabilité unique
Théorie
Le principe stipule : une classe ne doit avoir qu’une seule raison de changer. Cela signifie que chaque classe doit être responsable d’une seule fonctionnalité ou logique métier spécifique.
Anti-patron (violation du SRP)
<?phpclass OrderProcessor { public function process(Order $order): void { // 1. Validation de la commande if (empty($order->getItems())) { throw new \\InvalidArgumentException('Order has no items'); } // 2. Sauvegarde en BDD $db = new \\PDO('mysql:host=localhost;dbname=shop', 'user', 'pass'); $stmt = $db->prepare('INSERT INTO orders ...'); $stmt->execute([...]); // 3. Envoi d’email mail($order->getCustomerEmail(), 'Commande confirmée', '...'); // 4. Journalisation file_put_contents('/var/log/orders.log', 'Order processed: '.$order->getId()); }}?>Ici, la classe OrderProcessor fait trop de choses : valide, travaille avec la BDD, envoie des emails, journalise. La violation du SRP conduit à ce qu’une modification de la logique d’envoi d’email nécessite de modifier la classe responsable du traitement des commandes.
Refactoring avec respect du SRP
<?phpclass OrderValidator { public function validate(Order $order): void { if (empty($order->getItems())) { throw new \\InvalidArgumentException('Order has no items'); } }}
class OrderRepository { public function save(Order $order): void { // Logique de sauvegarde en BDD }}
class EmailNotifier { public function sendOrderConfirmation(Order $order): void { // Logique d’envoi d’email }}
class Logger { public function log(string $message): void { // Journalisation }}
class OrderProcessor { public function __construct( private OrderValidator $validator, private OrderRepository $repository, private EmailNotifier $notifier, private Logger $logger ) {} public function process(Order $order): void { $this->validator->validate($order); $this->repository->save($order); $this->notifier->sendOrderConfirmation($order); $this->logger->log('Order processed: '.$order->getId()); }}?>Maintenant, chaque classe a une responsabilité unique. La modification de la logique d’email n’affecte pas le travail avec la BDD.
2. Open-Closed Principle (OCP) — Principe d’ouverture/fermeture
Théorie
Les entités logicielles doivent être ouvertes à l’extension, mais fermées à la modification. En d’autres termes, vous devez pouvoir ajouter de nouvelles fonctionnalités sans modifier le code existant.
Anti-patron
<?phpclass PaymentProcessor { public function process(string $type, float $amount): void { if ($type === 'credit_card') { // Traitement de la carte de crédit } elseif ($type === 'paypal') { // Traitement PayPal\