Il est possible de modifier le comportement de la classe mère en redéfinissant ou en en surchargeant ses méthodes dans la classe fille.
S'il existe une différence théorique entre la redéfinition et la surcharge , les deux aboutissent finalement au même résultat : une méthode de la classe mère est réécrite dans la classe fille.

La méthode de la classe mére est masquée par sa nouvelle définition dans la classe fille. Il est pourtant toujours possible d'invoquer la méthode originale de la classe mère, en préfixant cet appel avec le mot-clé `parent` et l'opérateur de résolution de portée `::`.

### Redéfinition de méthode

On dit qu'une méthode est redéfinie quand elle a la même signature dans la classe mère et dans la classe fille. Les 2 méthodes ont donc le même nombre d'arguments et ces arguments sont du même type.

Comme vous avez pu le remarquer dans notre exemple, la méthode `decrire()` est incompléte pour les guitares électriques car elle ne donne pas d'information sur le nombre de micros et la présence ou non d'un vibrato. Cette méthode va donc être redéfinie dans la classe fille GuitareElectrique pour afficher ces éléments.

Exemple : redéfinition de méthode
<?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>"; } public function decrire() { echo '<h4>Guitare ', $this->son, '</h4>', $this->modele, '<br>', $this->cordes, ' cordes<br>', $this->micros, ' micros<br>', (($this->vibrato) ? 'avec':'sans'),' vibrato<br>', $this->prix, ' &euro;'; } } // Fin de la classe GuitareElectrique htmlDebut('Redéfinition de la méthode decrire()'); $g1 = new Guitare('Guild D120', 639, 6, Guitare::SON_A); $g1->decrire(); // méthode de la classe Guitare $g2 = new GuitareElectrique('Gretsch G5420', 869, 6, 2, true); $g2->decrire(); // méthode de la classe GuitareElectrique $g3 = new GuitareElectrique('Fender Precision', 724, 4, 2, false); $g3->decrire(); // méthode de la classe GuitareElectrique htmlFin(); ?>

On pourrait aussi réécrire la méthode en faisant d'abord appel à celle de la classe parent, puis en ajoutant l'affichage des informations propres aux guitares électriques.

Exemple : redéfinition de méthode
<?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>"; } public function decrire() { parent::decrire(); echo '<br>', $this->micros, ' micros<br>', (($this->vibrato) ? 'avec' : 'sans'), ' vibrato'; } } // Fin de la classe GuitareElectrique htmlDebut('Redéfinition de la méthode decrire()'); $g1 = new Guitare('Ibanez AEB8E-BK', 399, 4, Guitare::SON_EA); $g1->decrire(); // méthode de la classe Guitare $g2 = new GuitareElectrique('Danelectro 59 dano', 449, 12, 2, false); $g2->decrire(); // méthode de la classe GuitareElectrique $g3 = new GuitareElectrique('Fender Precision', 724, 4, 2, false); $g3->decrire(); // méthode de la classe GuitareElectrique htmlFin(); ?>

### Surcharge de méthode

On dit qu'une méthode est surchargée quand elle n'a pas la même signature dans la classe mère et dans la classe fille. Les 2 méthodes ont donc un nombre d'arguments différents, ou des types d'arguments différents, ou à la fois un nombre et des types d'arguments différents.

A titre d'exemple, nous allons surcharger la méthode `setRemise()` qui permet de définir un taux de remise pour le prix d'une guitare. Il a été décidé que pour les guitares électriques, on pouvait avoir non seulement une remise, mais également une paire de cables (des jacks) offerte. On va réécrire la méthode `setRemise()` dans la classe fille pour qu'elle accepte et traite maintenant 2 paramètres : un taux de remise et la valeur en euros d'une paire de jacks. On modifiera aussi la méthode `decrire()` pour afficher cette offre éventuelle.

Exemple : surcharge de méthode
<?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 setRemise($taux) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } } public function getPrix() { $rem = ceil($this->prix * $this->remise / 100); return $this->prix - $rem; } public function decrire() { echo '<h4>Guitare ', $this->son, '</h4>', $this->modele, '<br>', $this->cordes, ' cordes<br>', $this->getPrix(), ' &euro;'; } } // Fin de la classe Guitare class GuitareElectrique extends Guitare { private $micros, $vibrato, $jack = 0; public function __construct($p1, $p2, $p3, $p4, $p5) { parent::__construct($p1, $p2, $p3, parent::SON_E); $this->micros = $p4; $this->vibrato = $p5; } public function setRemise($taux, $val = 0) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } if (preg_match('/^\d{0,3}(\.\d{0,2})?$/', $val)) { $this->jack = $val; } } public function decrire() { parent::decrire(); echo '<br>', $this->micros, ' micros<br>', (($this->vibrato) ? 'avec' : 'sans'), ' vibrato'; if ($this->jack > 0) { echo '<br>Jacks offerts (',$this->jack,' &euro;)'; } } } // Fin de la classe GuitareElectrique htmlDebut('Surcharge de la méthode setRemise()'); $g1 = new GuitareElectrique('Gretsch G5622T', 995, 6, 3, true); $g1->setRemise(10, 80); // 10% de remise et 80 euros de jacks $g1->decrire(); $g2 = new GuitareElectrique('Gibson SG', 689, 6, 2, false); $g2->setRemise(20); // 20% de remise, pas de jack $g2->decrire(); $g3 = new GuitareElectrique('Fender Strat', 609, 6, 3, true); $g3->setRemise(0, 50); // 0% de remise, 50 euros de jacks $g3->decrire(); htmlFin(); ?>

### Reprise de l'exemple

L'affichage des médias étant un plus, il a été décidé qu'il devait être généralisé à toutes les guitares. On va donc le déplacer de la classe fille dans la classe mère. On y est obligé car il n'est pas possible à une classe mère d'atteindre les membres d'une fille (il n'y pas de mot-clé `child` comme il y a un mot-clé `parent`).

Cette modification du code des 2 classes n'a aucune influence sur le code "externe" qui les utilise puisque grâce à l'héritage c'est le moteur PHP qui invoquera la méthode correctement. A remarquer qu'il est important que le code des classes soit mis dans des fichiers séparés de ceux contenant le code qui les utilise car les modifications en sont d'autant plus simplifiées. Pour rappel, si ça n'est pas fait dans les exemples c'est uniquement par souci de simplification.

La méthode `decrire()` est légérement modifiée pour afficher également les médias associés à l'objet.

Exemple : reprise de l'exemple
<?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 setRemise($taux) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } } public function getPrix() { $rem = ceil($this->prix * $this->remise / 100); return $this->prix - $rem; } public function getMedias() { $fichier = str_replace(' ', '_', $this->modele); $fichier = strtolower($fichier); return "<div style=float:right;margin-bottom:1em> <audio src=audio/$fichier.mp3 controls style='width: 80px;'></audio> <img src=visuels/$fichier.jpg></div>"; } public function decrire() { $prix = '<span style=float:right>'; $net = $this->getPrix(); if ($net!=$this->prix) $prix .="<s>$this->prix</s>"; $prix .= " $net €</span>"; echo '<h4>Guitare ', $this->son, $prix, '</h4>', $this->getMedias(), $this->modele, '<br>', $this->cordes, ' cordes'; } } // Fin de la classe Guitare class GuitareElectrique extends Guitare { private $micros, $vibrato, $jack = 0; public function __construct($p1, $p2, $p3, $p4, $p5) { parent::__construct($p1, $p2, $p3, parent::SON_E); $this->micros = $p4; $this->vibrato = $p5; } public function setRemise($taux, $val = 0) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } if (preg_match('/^\d{0,3}(\.\d{0,2})?$/', $val)) { $this->jack = $val; } } public function decrire() { parent::decrire(); echo '<br>', $this->micros, ' micros<br>', (($this->vibrato) ? 'avec' : 'sans'), ' vibrato'; if ($this->jack > 0) { echo '<br>Jacks offerts (',$this->jack,' &euro;)'; } } } // Fin de la classe GuitareElectrique htmlDebut('Reprise de l\'exemple'); $g1 = new Guitare('Dobro Hound Dog', 453, 6, Guitare::SON_R); $g1->setRemise(20); $g1->decrire(); $g2 = new GuitareElectrique('Gretsch G5622T', 995, 6, 3, true); $g2->setRemise(10, 80); $g2->decrire(); $g3 = new GuitareElectrique('Fender Strat', 609, 6, 3, true); $g3->setRemise(0, 50); $g3->decrire(); htmlFin(); ?>

### Exercice : Etendre une classe

Nous avons décidé d'étendre la vente de guitares aux guitares électriques double manches. Nous trouverons dans notre catalogue les modèles suivants :

Modéle | Prix | Manche haut | Manche bas |
BC Rich Double Neck | 990 € | 12 cordes 2 micros Sans vibrato | 6 cordes 2 micros Sans vibrato |
Danelectro DB604 | 799 € | 4 cordes 2 micros Sans vibrato | 6 cordes 2 micros Sans vibrato |
Gretsch G5566 Jet | 1329 € | 6 cordes 2 micros Avec vibrato | 6 cordes 2 micros Avec vibrato |
Harley Benton 612 | 498 € | 12 cordes 2 micros Sans vibrato | 6 cordes 2 micros Sans vibrato |

Etendez la classe GuitareElectrique avec la classe Guitare2Manches pour gérer les guitares doubles manches. Le constructeur de la classe reçoit un tableau contenant les valeurs pour initialiser les attributs. Pour simplifier, on considére que les valeurs sont correctes et on ne fait pas de validation dans le constructeur. La méthode `decrire()` doit afficher les informations sur les 2 manches.

Créez une classe Stock responsable de l'instanciation de ces guitares. Les instances des guitares seront gardées dans un tableau. Le constructeur de la classe Stock ira chercher les informations sur les guitares dans le fichier texte dont le nom lui sera passé en paramètre. Le fichier `stock/guitares2manches.txt` contient les informations pour les instanciations des guitares :

    BC Rich Double Neck|990|12|2|0|6|2|0
    Danelectro DB604|799|4|2|0|6|2|0
    Gretsch G5566 Jet|1329|6|2|1|6|2|1
    Harley Benton 612|498|12|2|0|6|2|0

L'affichage de ce stock de guitares sera réalisé par la méthode `afficher()` de la classe Stock.

Une solution possible

Exercice : étendre une classe
<?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 setRemise($taux) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } } public function getPrix() { $rem = ceil($this->prix * $this->remise / 100); return $this->prix - $rem; } // Méthode ajoutée car besoin dans la sous-sous-classe public function getPrixHTML() { $prix = '<span style=float:right>'; $net = $this->getPrix(); if ($net!=$this->prix) $prix .="<s>$this->prix</s>"; return "$prix $net &euro;</span>"; } public function getMedias() { $fichier = str_replace(' ', '_', $this->modele); $fichier = strtolower($fichier); return "<div style=float:right;margin-bottom:1em> <audio src=audio/$fichier.mp3 controls style='width: 80px;'></audio> <img src=visuels/$fichier.jpg></div>"; } public function decrire() { echo '<h4>Guitare ', $this->son, $this->getPrixHTML(), '</h4>', $this->getMedias(), $this->modele, '<br>', $this->cordes, ' cordes'; } } // Fin de la classe Guitare class GuitareElectrique extends Guitare { // Modification de la visibilité des attributs pour // qu'ils soient visibles de la sous-classe protected $micros, $vibrato, $jack = 0; public function __construct($p1, $p2, $p3, $p4, $p5) { parent::__construct($p1, $p2, $p3, parent::SON_E); $this->micros = $p4; $this->vibrato = $p5; } public function setRemise($taux, $val = 0) { if (is_numeric($taux) && estEntre($taux, 0, 100)) { $this->remise = $taux; } if (preg_match('/^\d{0,3}(\.\d{0,2})?$/', $val)) { $this->jack = $val; } } public function decrire() { parent::decrire(); echo '<br>', $this->micros, ' micros<br>', (($this->vibrato) ? 'avec' : 'sans'), ' vibrato'; if ($this->jack > 0) { echo '<br>Jacks offerts (',$this->jack,' &euro;)'; } } } // Fin de la classe GuitareElectrique class Guitare2Manches extends GuitareElectrique { private $cordes2, $micros2, $vibrato2; public function __construct($t) { $p = explode('|', $t); parent::__construct($p[0], $p[1], $p[2], $p[3], $p[4]); $this->cordes2 = $p[5]; $this->micros2 = $p[6]; $this->vibratos2 = $p[7]; } // Méthode entièrement redéfinie public function decrire() { echo '<h4>Guitare ', $this->son, $this->getPrixHTML(), '</h4>', $this->getMedias(), $this->modele, '<br>'; echo '<strong>Manche haut</strong><br>', $this->cordes, ' cordes<br>', $this->micros, ' micros<br>', (($this->vibrato) ? 'avec' : 'sans'), ' vibrato'; echo '<br><strong>Manche bas</strong><br>', $this->cordes2,' cordes<br>', $this->micros2, ' micros<br>', (($this->vibrato2) ? 'avec' : 'sans'),' vibrato'; if ($this->jack > 0) { echo '<br>Jacks offerts (',$this->jack,' &euro;)'; } } } // Fin de la classe Guitare2manches class Stock { private $produits = array(); public function __construct($fichier) { if (! is_file($fichier)) { exit("$fichier n'est pas un fichier"); } // Lecture du fichier et instanciation des produits foreach (file($fichier) as $enreg) { $this->produits[] = new Guitare2Manches($enreg); } } public function afficher() { htmlInfo('Modèles en stock'); foreach ($this->produits as $p) { $p->decrire(); } } } // Fin de la classe Stock htmlDebut('Etendre une classe'); $stock = new Stock('stock/guitares2manches.txt'); $stock->afficher(); htmlFin(); ?>