SOLID est un acronyme regroupant les cinq premiers principes majeurs de conception logicielle orientée objet (POO). Appliqués avec discernement, ils rendent le code plus facile à maintenir, plus lisible, plus flexible et plus robuste. Voici chacun d'eux, appliqué à PHP.
S — Responsabilité unique (SRP)
Une classe ne devrait avoir qu'une seule raison de changer. Une classe fourre-tout doit être scindée en classes plus petites et ciblées. Ici, une classe User qui gère à la fois le stockage, le courriel de bienvenue et les permissions est divisée en trois.
class User { public function __construct(public string $name, public string $email) {} }
class UserRepository { public function save(User $u): void { /* écrit en base de données */ } }
class WelcomeMailer { public function send(User $u): void { /* envoie le courriel */ } }
class PermissionChecker { public function can(User $u, string $action): bool { /* ... */ } }O — Ouvert/fermé (OCP)
Le code doit être ouvert à l'extension, fermé à la modification : on étend par l'héritage et les interfaces plutôt qu'en réécrivant l'existant. Une classe Database câblée pour MySQL devrait être modifiée pour accepter PostgreSQL. La solution : une interface commune et une implémentation par base de données.
interface Database { public function connect(): void; }
class MySQLDatabase implements Database { public function connect(): void { /* ... */ } }
class PostgreSQLDatabase implements Database { public function connect(): void { /* ... */ } }L — Substitution de Liskov (LSP)
Une sous-classe doit pouvoir remplacer sa classe parente sans changer le comportement du programme. Elle respecte donc les signatures, les types de retour et les exceptions du parent. L'exemple classique : un Square qui étend Rectangle. Modifier une seule dimension fausse alors le calcul de l'aire, et la substitution échoue.
I — Ségrégation des interfaces (ISP)
Plusieurs petites interfaces spécifiques valent mieux qu'une grosse interface générale : chaque classe n'implémente que les méthodes dont elle a besoin. Une interface DatabaseOperations trop touffue gagne à être découpée.
interface Readable { public function find(int $id): ?array; }
interface Writable { public function insert(array $row): int; }
class ReportDatabase implements Readable { /* lecture seule */ }
class AppDatabase implements Readable, Writable { /* lecture et écriture */ }D — Inversion des dépendances (DIP)
Les modules de haut niveau ne devraient pas dépendre des modules de bas niveau : les deux dépendent d'abstractions. On injecte donc une interface plutôt que d'instancier une classe concrète.
class OrderService {
public function __construct(private Database $db) {} // dépend de l'abstraction
}
$service = new OrderService(new MySQLDatabase());En résumé
SOLID n'est pas une religion, mais un ensemble de repères. Appliquez-le quand la complexité le justifie, et vous obtiendrez un code que vous aurez plaisir à relire dans six mois.
Lectures connexes : Les avantages de PHP et Les 10 meilleures façons d'apprendre à programmer en PHP.