Les principes SOLID en pratique
Appliquez les cinq principes SOLID à de vraies classes PHP.
Les principes SOLID en pratique est une leçon PHP Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage PHP Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours PHP Academy comprend 4 leçons au total.
Pourquoi SOLID
SOLID regroupe cinq principes de conception qui rendent le PHP orienté objet flexible, testable et résistant à la dégradation. Ce ne sont pas des règles à suivre aveuglément, mais des heuristiques qui réduisent le couplage et clarifient les responsabilités. Dans cette leçon, nous appliquons chaque principe à des classes PHP concrètes que vous pourriez réellement mettre en production.
- SResponsabilité unique
- OOuvert/Fermé
- LSubstitution de Liskov
- ISégrégation des interfaces
- DInversion des dépendances
Responsabilité unique
Une classe ne devrait avoir qu’une seule raison de changer. Une classe qui crée un rapport, le met en forme en HTML et l’envoie par e-mail a trois raisons de changer. Séparez la persistance, la mise en forme et le transport.
Ci-dessous, Invoice modélise uniquement les données ; le rendu et l’enregistrement sont gérés ailleurs.
<?php
final class Invoice {
public function __construct(
public readonly string $number,
public readonly int $cents
) {}
public function total(): float { return $this->cents / 100; }
}
final class InvoiceRenderer {
public function toText(Invoice $i): string {
return sprintf('Invoice %s: $%.2f', $i->number, $i->total());
}
}
$i = new Invoice('INV-1', 12500);
echo (new InvoiceRenderer())->toText($i), PHP_EOL;
SRP : repérer le problème
La violation classique de SRP est une classe dont le nom contient et, ou un Manager qui s’occupe de tout. Soyez attentif aux méthodes qui changent pour des raisons métier sans rapport. Si une modification de la règle fiscale et une modification de la mise en page PDF touchent toutes deux la même classe, celle-ci a trop de responsabilités.
Principe Ouvert/Fermé
Les entités logicielles devraient être ouvertes à l’extension et fermées à la modification. L’ajout d’un nouveau type de remise ne devrait pas obliger à modifier un immense switch. Utilisez le polymorphisme : chaque règle possède sa propre classe qui implémente une interface commune.
<?php
interface Discount { public function apply(float $total): float; }
final class PercentOff implements Discount {
public function __construct(private float $pct) {}
public function apply(float $t): float { return $t * (1 - $this->pct / 100); }
}
final class FlatOff implements Discount {
public function __construct(private float $amount) {}
public function apply(float $t): float { return max(0, $t - $this->amount); }
}
function checkout(float $total, Discount ...$discounts): float {
foreach ($discounts as $d) { $total = $d->apply($total); }
return $total;
}
echo checkout(100, new PercentOff(10), new FlatOff(5)), PHP_EOL; // 85
Substitution de Liskov
Les sous-types doivent pouvoir être utilisés partout où leur type de base est attendu, sans surprendre l’appelant. L’exemple célèbre suivant : Square extends Rectangle enfreint LSP, car définir la largeur ne doit pas modifier silencieusement la hauteur. Préférez les modéliser comme des types distincts derrière une interface commune Shape.
<?php
interface Shape { public function area(): float; }
final class Rectangle implements Shape {
public function __construct(private float $w, private float $h) {}
public function area(): float { return $this->w * $this->h; }
}
final class Square implements Shape {
public function __construct(private float $side) {}
public function area(): float { return $this->side ** 2; }
}
$shapes = [new Rectangle(2, 3), new Square(4)];
foreach ($shapes as $s) { echo $s->area(), PHP_EOL; }
LSP et les contrats
LSP impose également des contraintes aux contrats des méthodes. Un sous-type peut assouplir les préconditions et renforcer les postconditions, mais jamais l’inverse. Lever un nouveau type d’exception que le type de base n’a jamais déclaré, ou renvoyer null lorsque le type de base garantit un objet, viole la substituabilité. Les types de retour covariants et les types de paramètres contravariants de PHP imposent une partie de ces règles au niveau des types.
Ségrégation des interfaces
Les clients ne devraient pas dépendre de méthodes qu’ils n’utilisent pas. Une grosse interface Worker avec work() et eat() oblige un RobotWorker à créer un bouchon pour eat(). Divisez-la en interfaces de rôles ciblées afin que chaque implémentation ne s’engage que sur ce qu’elle fait réellement.
<?php
interface Workable { public function work(): string; }
interface Feedable { public function eat(): string; }
final class Human implements Workable, Feedable {
public function work(): string { return 'coding'; }
public function eat(): string { return 'lunch'; }
}
final class Robot implements Workable {
public function work(): string { return 'welding'; }
}
foreach ([new Human(), new Robot()] as $w) { echo $w->work(), PHP_EOL; }
Inversion des dépendances
La politique de haut niveau devrait dépendre d’abstractions, et non de détails concrets. Injectez une interface plutôt qu’une classe codée en dur. Vous pourrez ainsi remplacer un expéditeur d’e-mails réel par une doublure dans les tests, et utiliser un autre fournisseur en production, sans modifier le composant qui l’utilise.
<?php
interface Mailer { public function send(string $to, string $body): void; }
final class SmtpMailer implements Mailer {
public function send(string $to, string $body): void {
echo "SMTP -> $to: $body" . PHP_EOL;
}
}
final class SignupService {
public function __construct(private Mailer $mailer) {}
public function register(string $email): void {
$this->mailer->send($email, 'Welcome!');
}
}
(new SignupService(new SmtpMailer()))->register('a@b.com');
DIP et le conteneur
L’Inversion des dépendances est le principe ; l’Injection des dépendances est une technique permettant de le respecter. Un conteneur DI (PSR-11) relie le SmtpMailer concret à l’abstraction Mailer à la racine de composition. Le composant appelant n’écrit jamais new SmtpMailer() : la dépendance du code source pointe donc vers l’abstraction, et non vers le détail.
<?php
// Composition root wiring (pseudo-container)
$bindings = [
Mailer::class => fn() => new SmtpMailer(),
];
$resolve = fn(string $id) => $bindings[$id]();
$service = new SignupService($resolve(Mailer::class));
$service->register('user@example.com');
SOLID ensemble
Les principes se renforcent mutuellement. ISP maintient des interfaces réduites afin que les injections DIP restent ciblées ; OCP repose sur un polymorphisme que LSP rend sûr ; SRP fournit les petites classes qui rendent tout cela possible. Visez une forte cohésion interne et un faible couplage entre les composants.
- N’abstrahissez pas excessivement une classe utilisée une seule fois.
- Introduisez une interface lorsqu’une seconde implémentation ou une doublure de test apparaît.
Pragmatisme
SOLID est un moyen, pas une fin. Une interface créée prématurément avec une seule implémentation ajoute une indirection sans bénéfice (« généralité spéculative »). Appliquez ces principes lorsque le changement survient réellement ou est clairement imminent. Refactoriser vers SOLID est peu coûteux une fois que vous disposez de tests ; y tendre aveuglément dès le premier jour est du gaspillage.
Vérification rapide
Quel principe le problème d’héritage Square/Rectangle enfreint-il ?
Récapitulatif
Vous avez appliqué les cinq principes SOLID à du PHP réel :
- SRP : une seule raison de changer par classe.
- OCP : étendre le comportement avec de nouvelles classes polymorphes, plutôt que modifier un switch.
- LSP : les sous-types respectent le contrat du type de base.
- ISP : de petites interfaces de rôles plutôt que de grosses interfaces.
- DIP : dépendre d’abstractions et injecter les détails à la racine de composition.
Utilisez-les pour guider le refactoring, et non comme un simple rituel.
Questions Fréquemment Posées
La leçon « Les principes SOLID en pratique » est-elle gratuite ?
Oui — le texte complet de « Les principes SOLID en pratique » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours PHP Academy, passe à CoddyKit PRO. Le cours PHP Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Les principes SOLID en pratique » ?
Appliquez les cinq principes SOLID à de vraies classes PHP. Tu pratiques PHP Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer PHP Academy ?
Aucune expérience préalable n'est requise. PHP Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Les principes SOLID en pratique » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon PHP Academy ?
Oui. Chaque leçon PHP Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Les principes SOLID en pratique
- Patrons de création : fabrique, constructeur, singleton
- Patrons structurels : adaptateur, décorateur, façade
- Patrons comportementaux : stratégie, observateur, commande