L'héritage comme l'encapsulation est un des principes fondamentaux de le programmation objet.

Un héritage est défini par la relation "est un" ou "est une" : une voiture est un véhicule, une guitare est un instrument de musique, PHP est un langage informatique.
Cette relation n'est pas symétrique : tous les véhicules ne sont pas des voitures, tous les instruments de musique ne sont pas des guitares et tous les programmes ne sont pas écrits en PHP.

### Principes

L'héritage permet de réutiliser du code et de définir de nouvelles classes à partir de classes existantes.

On va donc utiliser le code déjà écrit et testé d'une première classe (la classe de base) et ajouter de nouvelles fonctionnalités dans une seconde classe (la classe dérivée).

La classe de base est également appelée classe mère ou encore super-classe. Les 3 termes sont synonymes.

La classe dérivée est également appelée classe fille ou encore sous-classe. Les 3 termes sont synonymes.

La relation entre la classe mére et la classe fille se fait avec le mot-clé `extends` placé entre le nom des classes dans la définition de la classe fille.

syntaxe de extends

On dit que La classe fille hérite de la classe mére. Elle bénéficie de tous les attributs et de toutes les méthodes de la classe mére, si ils/elles ne sont pas `private`.

Pour qu'une classe fille puisse atteindre les attributs de sa classe mère, les attributs dans la classe mère doivent être `protected` ou `public` (à éviter).

Pour qu'une classe fille puisse invoquer les méthodes de sa classe mère, les méthodes dans la classe mère doivent être `public` ou `protected`.

Dans l'exemple suivant, nous allons étendre la classe Guitare pour qu'on puisse aussi gérer des guitares électriques. Par rapport aux guitares de notre classe Guitare, une guitare électrique a deux attributs supplémentaires : `micros` pour définir le nombre de micros et `vibrato` pour définir si la guitare est équipée ou non d'un vibrato. Remarque 1 : par souci de simplification du code, les valeurs passées aux constructeurs ne sont pas validées (il faudrait bien sûr le faire dans un développement réel). Remarque 2 : les attributs de la classe mère Guitare sont passés en visibilité `protected` pour que la classe fille GuitareElectrique puisse les atteindre. | héritage décrit avec le formalisme UML

Exemple : étendre une classe mère
<?php ob_start(); require('bib_fonctions.php'); class Guitare { protected $modele, $prix, $cordes, $remise, $son; const SON_A = 'acoustique'; const SON_EA = 'électro-acoustique'; const SON_R = 'à résonnateur'; const SON_E = 'électrique'; public function __construct($p1, $p2, $p3, $p4) { $this->modele = $p1; $this->prix = $p2; $this->cordes = $p3; $this->son = $p4; $this->remise = 0; } public function decrire() { echo '<h4>Guitare ', $this->son, '</h4>', $this->modele, '<br>', $this->cordes, ' cordes<br>', $this->prix, ' &euro;'; } } // Fin de la classe Guitare class GuitareElectrique extends Guitare { private $micros, $vibrato; public function __construct($p1, $p2, $p3, $p4, $p5) { $this->modele = $p1; $this->prix = $p2; $this->cordes = $p3; $this->micros = $p4; $this->vibrato = $p5; $this->son = parent::SON_E; $this->remise = 0; } } // Fin de la classe GuitareElectrique htmlDebut('Etendre une classe mére'); $g1 = new Guitare('Gretsch Falcon', 599, 12, Guitare::SON_A); $g1->decrire(); $g2 = new GuitareElectrique('Gibson SG', 689, 6, 2, false); $g2->decrire(); $g3 = new GuitareElectrique('Fender Strat', 609, 6, 3, true); $g3->decrire(); htmlFin(); ?>

Le constructeur de la classe mère n'est pas appelé automatiquement quand on instancie la classe fille. Si nécessaire il doit être appelé explicitement dans le constructeur de la classe fille. On utilise alors l'opérateur de résolution de portée `::` précédé du mot-cle `parent`. On a fait la même chose dans l'exemple précédent pour faire référence dans la classe fille à la constante `SON_E` de la classe mère.

Exemple : utiliser le constructeur de la classe mère
<?php ob_start(); require('bib_fonctions.php'); class Guitare { protected $modele, $prix, $cordes, $remise, $son; const SON_A = 'acoustique'; const SON_EA = 'électro-acoustique'; const SON_R = 'à résonnateur'; const SON_E = 'électrique'; public function __construct($p1, $p2, $p3, $p4) { $this->modele = $p1; $this->prix = $p2; $this->cordes = $p3; $this->son = $p4; $this->remise = 0; } public function decrire() { echo '<h4>Guitare ', $this->son, '</h4>', $this->modele, '<br>', $this->cordes, ' cordes<br>', $this->prix, ' &euro;'; } } // Fin de la classe Guitare class GuitareElectrique extends Guitare { private $micros, $vibrato; public function __construct($p1, $p2, $p3, $p4, $p5) { parent::__construct($p1, $p2, $p3, parent::SON_E); $this->micros = $p4; $this->vibrato = $p5; } } // Fin de la classe GuitareElectrique htmlDebut('Utiliser le constructeur de la classe mére'); $g1 = new Guitare('Gretsch Falcon', 599, 12, Guitare::SON_A); $g1->decrire(); $g2 = new GuitareElectrique('Gibson SG', 689, 6, 2, false); $g2->decrire(); $g3 = new GuitareElectrique('Fender Strat', 609, 6, 3, true); $g3->decrire(); htmlFin(); ?>

L'héritage multiple n'est pas possible : une classe fille ne peut pas avoir plusieurs classes méres.
Une classe mère peut quant à elle avoir plusieurs classe filles.
L'héritage multi-niveaux est possible : une classe fille peut avoir une classe mère, une classe grand-mère, une classe arrière grand-mére, etc.

héritage

### Extension, spécialisation

L'ajout de fonctionnalités dans la classe fille se fait en y ajoutant des nouvelles caractéristiques (ie des nouveaux attributs) et des nouvelles actions (ie des nouvelles méthodes. La classe fille étend ainsi les capacités de la classe mére. On dit également qu'une classe fille est une spécialisation de la classe mére : elle "travaille" sur un domaine plus pointu que la classe mére.

Dans l'exemple précédent on a ajouté 2 nouveaux attributs à la classe mére. Il suffit de les définir dans la classe fille comme n'importe quel autre attribut. Remarque : une classe mére n'a pas accès aux nouveaux attributs définis dans sa classe fille, et ce, quelque soit la visibilité de ces attributs.

Pour ajouter de nouvelle méthodes à la classe fille, il suffit de les définir comme n'importe quelle autre méthode. Remarque : une classe mére n'a pas accès aux nouvelles méthodes définies dans sa classe fille, et ce, quelque soit la visibilité de ces attributs.

A titre d'exemple, nous allons ajouter une nouvelle méthode dans la classe fille GuitareElectrique. Cette méthode s'appelle `getMedias()` et donnera le code HTML pour afficher une photo de la guitare et jouer un extrait sonore.

Le nom des fichiers est fait par transformation de l'attribut `modele` auquel on ajoute l'extension .jpg pour les images et .mp3 pour l'audio. Les fichiers images sont le répertoire visuel et les fichiers audio dans le répertoire audio.

Le code de la méthode est le suivant :

    public function getMedias() {
    	$fichier = str_replace(' ', '_', $this->modele);
    	$fichier = strtolower($fichier);
    	return "<div><img src=visuels/$fichier.jpg>
    			<audio src=audio/$fichier.mp3 controls
    			style='width: 100px'></audio></div>";
    }

Exemple : Méthode spécifique dans la classe fille
<?php ob_start(); require('bib_fonctions.php'); class Guitare { protected $modele, $prix, $cordes, $remise, $son; const SON_A = 'acoustique'; const SON_EA = 'électro-acoustique'; const SON_R = 'à résonnateur'; const SON_E = 'électrique'; public function __construct($p1, $p2, $p3, $p4) { $this->modele = $p1; $this->prix = $p2; $this->cordes = $p3; $this->son = $p4; $this->remise = 0; } public function decrire() { echo '<h4>Guitare ', $this->son, '</h4>', $this->modele, '<br>', $this->cordes, ' cordes<br>', $this->prix, ' &euro;'; } } // Fin de la classe Guitare class GuitareElectrique extends Guitare { private $micros, $vibrato; public function __construct($p1, $p2, $p3, $p4, $p5) { parent::__construct($p1, $p2, $p3, parent::SON_E); $this->micros = $p4; $this->vibrato = $p5; } public function getMedias() { $fichier = str_replace(' ', '_', $this->modele); $fichier = strtolower($fichier); return "<div><img src=visuels/$fichier.jpg> <audio src=audio/$fichier.mp3 controls style='width: 100px'></audio></div>"; } } // Fin de la classe GuitareElectrique htmlDebut('Méthode spécifique dans la classe fille'); $g1 = new GuitareElectrique('Fender Strat', 609, 6, 3, true); $g1->decrire(); echo $g1->getMedias(); $g2 = new GuitareElectrique('Gretsch G5420', 869, 6, 2, true); $g2->decrire(); echo $g2->getMedias(); htmlFin(); ?>