L'héritage

Résumé Support Quiz

Dans ce chapitre, nous allons voir le principe de l'héritage en PHP, ainsi que la visibilité des propriétés et des méthodes. Ces notions permettent de mieux organiser le code lorsque plusieurs classes partagent un comportement commun, tout en ayant quelques différences.

L'idée est d'éviter de recopier la même logique dans plusieurs classes. Une classe peut reprendre le fonctionnement d'une autre, puis modifier uniquement les parties qui doivent changer.

Transformer une logique en objet

Avant de parler d'héritage, on peut commencer par déplacer une logique existante dans une classe. Une classe permet de regrouper les informations nécessaires et les méthodes qui travaillent avec ces informations.

<?php class Compteur { public $fichier; public function __construct(string $fichier) { $this->fichier = $fichier; } }

Le constructeur reçoit ici une valeur nécessaire au fonctionnement de l'objet et la stocke dans une propriété. Cette propriété pourra ensuite être réutilisée par les autres méthodes de la classe.

$compteur = new Compteur(__DIR__ . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'counter');

L'intérêt est que l'objet garde les informations dont il a besoin. On n'a donc pas à repasser systématiquement les mêmes paramètres à chaque fonction.

Ajouter des méthodes d'instance

Une fois les données stockées dans l'objet, on peut ajouter des méthodes qui utilisent ces propriétés. Ces méthodes décrivent les actions possibles sur l'objet.

class Compteur { public $fichier; public function __construct(string $fichier) { $this->fichier = $fichier; } public function incrementer(): void { $compteur = 1; if (file_exists($this->fichier)) { $compteur = (int)file_get_contents($this->fichier); $compteur++; } file_put_contents($this->fichier, $compteur); } public function recuperer(): int { if (!file_exists($this->fichier)) { return 0; } return (int)file_get_contents($this->fichier); } }

On peut ensuite utiliser l'objet sans se soucier de la logique interne :

$compteur->incrementer(); $vues = $compteur->recuperer();

Cette première étape montre l'intérêt des classes : on rassemble la logique liée à un concept au même endroit, avec une API plus claire à utiliser depuis le reste de l'application.

Le problème de la duplication

On peut parfois avoir besoin d'une classe très proche d'une autre, avec seulement une petite différence de comportement. Une première solution serait de recopier toute la classe, puis de modifier la méthode concernée.

class DoubleCompteur { public $fichier; public function __construct(string $fichier) { $this->fichier = $fichier; } public function incrementer(): void { // Même logique que dans Compteur... } public function recuperer(): int { // Même logique, mais avec une petite différence... } }

Cette solution fonctionne, mais elle pose un problème : si la logique commune doit changer, il faudra la modifier à plusieurs endroits. C'est exactement le type de répétition que l'héritage permet d'éviter.

Hériter d'une classe

L'héritage permet de créer une classe qui reprend les propriétés et les méthodes d'une autre classe. Pour cela, on utilise le mot-clé extends.

<?php require __DIR__ . DIRECTORY_SEPARATOR . 'Compteur.php'; class DoubleCompteur extends Compteur { }

La classe qui hérite récupère automatiquement le fonctionnement de la classe parente. Même si elle ne contient pas encore de code, elle peut utiliser les méthodes définies dans la classe dont elle hérite.

$compteur = new DoubleCompteur($fichier); $compteur->incrementer(); echo $compteur->recuperer();

L'intérêt est de pouvoir créer une variante d'un comportement existant, sans recopier toute la logique.

Redéfinir une méthode

Une classe enfant peut modifier une méthode héritée. On parle alors de redéfinition de méthode. Il suffit de déclarer dans la classe enfant une méthode qui porte le même nom.

class DoubleCompteur extends Compteur { public function recuperer(): int { return parent::recuperer() * 2; } }

Le mot-clé parent permet d'appeler la méthode définie dans la classe parente. Cela évite de réécrire toute la logique si on veut simplement adapter le résultat.

On peut aussi ajouter de nouvelles méthodes dans la classe enfant. Elles seront disponibles uniquement sur cette classe et sur les classes qui en hériteraient ensuite.

class DoubleCompteur extends Compteur { public function recuperer(): int { return parent::recuperer() * 2; } public function demo(): void { // Méthode propre à cette classe. } }

L'héritage sert donc à exprimer qu'une classe fonctionne comme une autre, mais avec quelques différences ou fonctionnalités supplémentaires.

Comprendre la visibilité

Les mots-clés public, private et protected permettent de définir la visibilité d'une propriété ou d'une méthode. Cette visibilité indique depuis où l'élément peut être utilisé.

Avec public, l'élément est accessible depuis l'intérieur de la classe, mais aussi depuis l'extérieur.

class Compteur { public function recuperer(): int { return 0; } } $compteur->recuperer();

Avec private, l'élément est accessible uniquement à l'intérieur de la classe qui le définit. Il ne peut pas être appelé depuis l'extérieur, ni utilisé directement dans une classe enfant.

class Compteur { private $fichier; }

Avec protected, l'élément reste inaccessible depuis l'extérieur, mais il peut être utilisé dans la classe courante et dans les classes enfants.

class Compteur { protected $fichier; } class DoubleCompteur extends Compteur { public function recuperer(): int { return (int)file_get_contents($this->fichier) * 2; } }

On peut résumer les visibilités comme ceci :

  • public : accessible depuis l'intérieur et l'extérieur de la classe.
  • private : accessible uniquement dans la classe qui le définit.
  • protected : accessible dans la classe qui le définit et dans ses classes enfants.

Pourquoi ne pas tout mettre en public ?

On pourrait être tenté de tout rendre public pour ne jamais avoir de problème d'accès. Mais la visibilité sert aussi à organiser le code et à rendre l'intention plus claire.

Quand une propriété ou une méthode est privée ou protégée, on comprend qu'elle fait partie du fonctionnement interne de la classe. À l'inverse, ce qui est public représente ce que l'on est censé utiliser depuis l'extérieur.

Un bon réflexe consiste à rendre les éléments privés par défaut, puis à ouvrir uniquement ce qui doit réellement être utilisé :

  • si l'élément doit être appelé depuis l'extérieur, on le met en public.
  • s'il ne sert qu'à la classe elle-même, on le garde en private.
  • s'il doit aussi être accessible aux classes enfants, on le met en protected.

Le constructeur, lui, reste public, car il doit pouvoir être appelé au moment de créer l'objet.

Ces règles de visibilité s'appliquent aussi aux méthodes et propriétés statiques. On peut donc avoir public static, private static ou protected static.

Constantes de classe

Une classe peut aussi définir des constantes. Elles ressemblent à des propriétés statiques, mais leur valeur ne change pas.

class Compteur { const INCREMENT = 1; public function incrementer(): void { $compteur = 0; $compteur += self::INCREMENT; } }

Contrairement aux propriétés statiques, une constante ne s'appelle pas avec un $.

self::INCREMENT;

Une classe enfant peut redéfinir une constante, mais il faut faire attention au mot-clé utilisé pour y accéder.

class DoubleCompteur extends Compteur { const INCREMENT = 10; }

Si la classe parente utilise self::INCREMENT, self fera toujours référence à la classe dans laquelle la méthode est définie. Dans ce cas, la constante de la classe enfant ne sera pas utilisée.

Pour que PHP tienne compte de la classe réellement appelée, on peut utiliser static::INCREMENT. C'est ce qu'on appelle la résolution statique à la volée.

class Compteur { const INCREMENT = 1; public function incrementer(): void { $compteur = 0; $compteur += static::INCREMENT; } }

Avec static::, PHP regarde le contexte réel d'exécution et peut donc utiliser la constante redéfinie dans une classe enfant.

À retenir

L'héritage permet de créer une classe à partir d'une autre avec extends. La classe enfant récupère les propriétés et méthodes de la classe parente, puis peut redéfinir certaines méthodes ou ajouter son propre comportement.

La visibilité permet de mieux contrôler ce qui fait partie de l'API publique d'une classe et ce qui relève de son fonctionnement interne. public, private et protected ne servent pas seulement à éviter des erreurs : ils aident aussi à rendre le code plus lisible et mieux organisé.

Ressources

Pour aller plus loin, vous pouvez consulter la documentation officielle PHP sur l'héritage, la visibilité et la résolution statique à la volée.