Une interface, c'est un contrat
Une interface liste des méthodes sans les implémenter : c'est une promesse. Une classe qui implements une interface s'engage à fournir toutes ces méthodes. Le reste du code peut alors lui faire confiance sans connaître son type exact — c'est le polymorphisme vu dans le cours POO, en PHP.
interface MoyenPaiement {
public function payer(float $montant): string; // signature, pas de corps
}
class CarteBancaire implements MoyenPaiement {
public function payer(float $montant): string {
return "Payé $montant € par carte";
}
}
class Paypal implements MoyenPaiement {
public function payer(float $montant): string {
return "Payé $montant € via PayPal";
}
}
Une classe peut implémenter plusieurs interfaces (séparées par des virgules) — contrairement à extends qui n'autorise qu'un seul parent.
Coder contre l'interface, pas l'implémentation
La règle d'or : une fonction doit dépendre du contrat (l'interface), pas d'une classe précise. Ainsi elle accepte n'importe quel moyen de paiement, présent ou futur.
// On type avec l'INTERFACE : accepte carte, PayPal, ou tout futur moyen
function encaisser(MoyenPaiement $moyen, float $montant): void {
echo $moyen->payer($montant) . "\n";
}
encaisser(new CarteBancaire(), 50);
encaisser(new Paypal(), 30);
// Demain : une classe ApplePay implements MoyenPaiement → marche sans rien changer ici
C'est le secret du code extensible : encaisser() ne sera jamais à modifier quand on ajoute un moyen de paiement. On branche une nouvelle classe qui respecte le contrat, point.
Polymorphisme : exécute
Une seule boucle, plusieurs types : chaque objet répond à sa façon au même appel payer().
<?php
interface MoyenPaiement {
public function payer(float $montant): string;
}
class CarteBancaire implements MoyenPaiement {
public function payer(float $m): string { return "💳 $m € par carte"; }
}
class Paypal implements MoyenPaiement {
public function payer(float $m): string { return "🅿 $m € via PayPal"; }
}
class Especes implements MoyenPaiement {
public function payer(float $m): string { return "💶 $m € en espèces"; }
}
$moyens = [new CarteBancaire(), new Paypal(), new Especes()];
foreach ($moyens as $moyen) { // ignore le type exact
echo $moyen->payer(20) . "\n";
}
?>
Sans remonter dans la leçon : à quoi sert le mot-clé implements, et pourquoi typer un paramètre avec MoyenPaiement plutôt qu'avec CarteBancaire ?
implements engage une classe à fournir toutes les méthodes promises par l'interface : c'est un contrat vérifié par PHP (sinon erreur). Typer avec MoyenPaiement au lieu de CarteBancaire permet à la fonction d'accepter n'importe quelle classe respectant le contrat (PayPal, espèces, un futur ApplePay) sans jamais la modifier : c'est coder contre l'interface, pas l'implémentation.Tu demandes à l'IA un moyen de paiement « chèque ». Elle te rend ceci. Ton rôle de relecteur : l'accepter tel quel ou le rejeter, et dire pourquoi.
class Cheque extends CarteBancaire {
public function payer(float $m): string {
return "🧾 $m € par chèque";
}
}
Cheque hérite de CarteBancaire alors qu'un chèque n'est pas une carte bancaire ; il ne réutilise rien d'elle et risque d'hériter d'un comportement qui n'a aucun sens (frais de carte, etc.). Le bon geste : implémenter directement le contrat avec class Cheque implements MoyenPaiement. On hérite pour un vrai lien « est-un », on implements pour partager un contrat entre classes sans parenté.PHP n'autorise qu'un seul parent (extends). Alors comment partager un même bout de code entre des classes sans lien de parenté ? Avec les traits.
An interface is a contract
An interface lists methods without implementing them: it's a promise. A class that implements an interface commits to providing all those methods. The rest of the code can then trust it without knowing its exact type — that's the polymorphism from the OOP course, in PHP.
interface MoyenPaiement {
public function payer(float $montant): string; // signature, no body
}
class CarteBancaire implements MoyenPaiement {
public function payer(float $montant): string {
return "Paid $montant € by card";
}
}
class Paypal implements MoyenPaiement {
public function payer(float $montant): string {
return "Paid $montant € via PayPal";
}
}
A class can implement several interfaces (comma-separated) — unlike extends which allows only one parent.
Code against the interface, not the implementation
The golden rule: a function should depend on the contract (the interface), not a specific class. That way it accepts any payment method, present or future.
// We type with the INTERFACE: accepts card, PayPal, or any future method
function encaisser(MoyenPaiement $moyen, float $montant): void {
echo $moyen->payer($montant) . "\n";
}
encaisser(new CarteBancaire(), 50);
encaisser(new Paypal(), 30);
// Tomorrow: a class ApplePay implements MoyenPaiement → works with no change here
That's the secret of extensible code: encaisser() will never need changing when you add a payment method. You plug in a new class that honors the contract, done.
Polymorphism: run it
One loop, several types: each object answers the same payer() call in its own way.
<?php
interface MoyenPaiement {
public function payer(float $montant): string;
}
class CarteBancaire implements MoyenPaiement {
public function payer(float $m): string { return "💳 $m € by card"; }
}
class Paypal implements MoyenPaiement {
public function payer(float $m): string { return "🅿 $m € via PayPal"; }
}
class Especes implements MoyenPaiement {
public function payer(float $m): string { return "💶 $m € in cash"; }
}
$moyens = [new CarteBancaire(), new Paypal(), new Especes()];
foreach ($moyens as $moyen) { // ignores the exact type
echo $moyen->payer(20) . "\n";
}
?>
PHP allows only one parent (extends). So how do you share the same bit of code between unrelated classes? With traits.