Tous les développeurs PHP objets ont un jour ou l’autre eu l’envie de faire du beau code avec des classes propres, mais se sont heurtés au fait que PHP ne gère pas l’héritage multiple.
Cet article vous propose une solution de contournement.
Prérequis: Version de PHP >= 5.4.0
Voici quelques classes d’exemples:
<?php class Vehicule { public $nom; public $nombreDePassagers; public $couleur; public $vitesseMax; } class Voiture extends Vehicule { public $nombreDeRoues; } class Autobus extends Vehicule { public $nombreDeRoues; } class Velo extends Vehicule { public $nombreDeRoues; } class Avion extends Vehicule { } class Bateau extends Vehicule { }
Dans l’exemple ci-dessus, Voiture, Autobus, Velo, Avion et Bateau sont tous des véhicules grâce à l’héritage simple.
Il est donc possible de tester si un objet est un véhicule avec le code suivant:
... $unAvion = new Avion(); if($unAvion instanceof Vehicule) { echo "unAvion est bien un véhicule !"; }
On remarque que la Voiture partage des caractéristiques avec Autobus et Velo : le nombre de roues !
On peut donc avoir envie de mutualiser ce code dans une classe « PeutRouler« .
<?php class PeutRouler { public $nombreDeRoues; } class Voiture extends Vehicule, PeutRouler // impossible hélas ! { } $uneVoiture = new Voiture(); if($uneVoiture instanceOf PeutRouler) { echo "cette voiture peut rouler !"; } $unBateau = new Bateau(); if(!($unBateau instanceOf PeutRouler)) { echo "ce Bateau ne peut pas rouler !"; }
Le code précédent n’est malheureusement pas possible en PHP car une classe ne peut en hériter que d’une seule autre !
Il est imaginable de décréter que Vehicule hérite de PeutRouler sauf qu’il existe aussi des véhicules qui ne peuvent pas rouler (Bateau) ce n’est donc pas souhaitable.
Solution : les Traits pour simuler un héritage multiple
Heureusement depuis PHP 5.4.0 il existe les Traits qui vont nous permettre de simuler un héritage multiple !
On va donc transformer PeutRouler en trait et l’utiliser dans la classe Voiture, Autobus et Velo
<?php trait PeutRouler { public $nombreDeRoues; } trait PeutVoler { public $vitesseDecrochage; } trait PeutFlotter { public $hauteurDeVagueMax; } class Vehicule { public $nom; public $nombreDePassagers; public $couleur; } class Voiture extends Vehicule { use PeutRouler; } class Autobus extends Vehicule { use PeutRouler; } class Velo extends Vehicule { use PeutRouler; } class Avion extends Vehicule { use PeutVoler; } class Bateau extends Vehicule { use PeutFlotter; }
PeutRouler est maintenant un Trait qui est utilisé dans les classes Voiture, Autobus et Velo.
Par contre, un trait fonctionne comme un copier/coller au moment de la compilation du code par PHP, le contenu du trait est donc « copié » tel quel dans la classe qui l’utilise, ce qui rend impossible le test suivant:
... $unBateau = new Bateau(); if($unBateau instanceOf PeutFlotter) { echo "ce Bateau peut flotter !"; }
Pour le rendre possible, on peut utiliser les Interfaces.
Voici le code final:
<?php // Pour éviter les confusions, j'indique en suffixe que c'est un Trait trait PeutRoulerTrait { public $nombreDeRoues; } // Pour éviter les confusions, j'indique en suffixe que c'est une Interface interface PeutRoulerInterface { } trait PeutVolerTrait { public $vitesseDecrochage; } interface PeutVolerInterface { } trait PeutFlotterTrait { public $hauteurDeVagueMax; } interface PeutFlotterInterface { } class Vehicule { public $nom; public $nombreDePassagers; public $couleur; } class Voiture extends Vehicule implements PeutRoulerInterface { use PeutRoulerTrait; } class Autobus extends Vehicule implements PeutRoulerInterface { use PeutRoulerTrait; } class Velo extends Vehicule implements PeutRoulerInterface { use PeutRoulerTrait; } class Avion extends Vehicule implements PeutRoulerInterface, PeutVolerInterface // il est possible d'implémenter de multiples interfaces sur une même classe { use PeutRoulerTrait; use PeutVolerTrait; } class Bateau extends Vehicule implements PeutFlotterInterface { use PeutFlotterTrait; }
il devient possible de tester si une voiture peut rouler grâce aux interfaces:
$uneVoiture = new Voiture(); if($uneVoiture instanceOf PeutRoulerInterface) { echo "cette voiture peut rouler avec ".$uneVoiture->nombreDeRoues." roues"; } $unAvion = new Avion(); if($unAvion instanceof PeutVolerInterface) { echo "cet Avion peut voler !"; } if($unAvion instanceof PeutRoulerInterface) { echo "cet Avion peut aussi rouler (sur la piste!) avec ".$unAvion->nombreDeRoues." roues"; }
Et voila ! en combinant héritage simple, traits et interfaces il vous est désormais possible de simuler l’héritage multiple en PHP sans duplication de code et avec possibilité de tester le type de l’instance.
Laisser un commentaire