En PHP, une classe hérite d'une autre avec extends : class Dog extends Animal donne à Dog toutes les propriétés et méthodes publiques et protégées d'Animal. L'enfant peut ajouter de nouvelles méthodes, redéfinir des méthodes héritées en déclarant une méthode du même nom, et appeler l'original avec parent::method().
Dog n'a pas de constructeur, il utilise donc celui d'Animal, c'est pourquoi new Dog('Rex') fonctionne. Une classe enfant ne peut étendre qu'un seul parent ; PHP n'a pas d'héritage multiple de classes.
Appeler la méthode parent avec parent::
Redéfinir remplace entièrement la méthode du parent. Pour l'étendre au lieu de la remplacer, appelez parent::method() depuis l'enfant et construisez sur son résultat :
C'est pareil pour les constructeurs avec parent::__construct(...), que présente la page sur le constructeur, y compris ce qui se passe quand on l'oublie.
protected ou private dans les classes enfants
Un membre protected est caché au code extérieur mais visible par toutes les classes de la famille. Un membre private n'est visible que dans la classe qui le déclare, donc une classe enfant ne le voit pas du tout :
isset($this->pin) est faux dans l'enfant, car l'enfant n'a pas accès au $pin privé du parent, alors que la méthode propre du parent hasPin() le lit toujours. Utilisez protected pour ce sur quoi les sous-classes sont censées construire, et private pour les détails que vous voulez pouvoir changer librement.
Polymorphisme et instanceof
Du code écrit pour le type parent fonctionne avec chaque enfant. Chaque objet exécute sa propre version d'une méthode redéfinie, donc une seule boucle les gère tous. instanceof vérifie si un objet appartient à une classe ou à l'un de ses enfants :
Quand le parent ne doit jamais être utilisé seul (un simple Shape d'aire 0 n'a guère de sens), faites-en une classe abstraite et déclarez area() abstraite.
Règles de redéfinition : les signatures doivent rester compatibles
Une méthode qui en redéfinit une autre doit accepter au moins ce qu'acceptait le parent et renvoyer quelque chose d'utilisable par les appelants du parent. Vous pouvez ajouter un paramètre facultatif, élargir le type d'un paramètre ou restreindre le type de retour ; vous ne pouvez pas ajouter de paramètre obligatoire ni rendre privée une méthode publique.
Remplacez string $sep = ',' par un string $sep obligatoire et PHP refuse de compiler la classe avec une erreur fatale (« Declaration of CsvExporter::export(array sep): string must be compatible with Exporter::export(array $rows): string »).
Classes et méthodes final
final arrête l'héritage à cet endroit. Une méthode final ne peut pas être redéfinie, et une final class ne peut pas être étendue. Les deux sont vérifiées à la compilation du fichier, donc le script ne démarre pas du tout :
<?php
class Payment
{
final public function charge(int $cents): string
{
return "charged $cents";
}
}
class FreePayment extends Payment
{
public function charge(int $cents): string
{
return 'free';
}
}
PHP Fatal error: Cannot override final method Payment::charge() in /home/index.php on line 12
Pour une classe final, le message est Class B cannot extend final class A. Marquez une méthode final quand le parent compte sur un comportement unique, par exemple une méthode qui vérifie les permissions avant toute autre chose.
Le piège des méthodes privées
Une méthode privée n'est pas héritée, donc une méthode enfant du même nom ne la redéfinit pas. Le code du parent continue d'appeler sa propre version privée, ce qui surprend ceux qui s'attendent à voir s'exécuter la méthode de l'enfant :
greet() affiche toujours Hello : le $this->word() du parent se résout vers la méthode privée du parent. Remplacez private par protected dans Greeter et relancez ; la méthode de l'enfant est maintenant une vraie redéfinition et greet() dit Bonjour.
Questions fréquentes
Comment fonctionne extends en PHP ?
class Dog extends Animal fait de Dog un enfant d'Animal. Un objet Dog a toutes les propriétés et méthodes publiques et protégées d'Animal, peut ajouter les siennes et peut remplacer (redéfinir) des méthodes héritées en déclarant une méthode du même nom.
Comment appeler la méthode parent en PHP ?
Utilisez parent::methodName() dans la méthode de l'enfant, par exemple return parent::describe() . ' and more';. Pour le constructeur, c'est parent::__construct(...).
PHP supporte-t-il l'héritage multiple ?
Non. Une classe ne peut étendre qu'une seule classe parente. Pour partager un comportement venant de plusieurs sources, implémentez plusieurs interfaces (class A implements B, C) et utilisez des traits (use Loggable, Timestamps;).
Que signifie final en PHP ?
Une méthode final ne peut pas être redéfinie par une classe enfant, et une final class ne peut pas du tout être étendue. Enfreindre l'une ou l'autre règle provoque une erreur fatale à la compilation de la classe, par exemple Cannot override final method A::f().
Une classe enfant peut-elle accéder à une propriété privée de son parent en PHP ?
Non. Un membre private n'appartient qu'à la classe qui le déclare, donc dans l'enfant $this->pin est une propriété non définie (un warning, puis null) et une méthode enfant du même nom ne redéfinit pas une méthode privée. Déclarez le membre protected quand les classes enfants en ont besoin.