Traits vs Héritage
Fait partie de la section Programmation Orientée Objet du Journey PHP de Coddy — leçon 55 sur 91.
Maintenant que vous comprenez comment fonctionnent les traits, clarifions quand utiliser les traits par rapport à l'héritage. Les deux permettent la réutilisation de code, mais ils servent des objectifs différents et ont des caractéristiques distinctes.
L'héritage établit une relation « est un ». Une classe Dog étendant Animal signifie qu'un chien est un animal. La classe enfant hérite de l'identité du parent et peut être utilisée partout où le type parent est attendu.
Les Traits fournissent une capacité « a un » (has-a). Lorsqu'une classe utilise un trait Loggable, elle possède une fonctionnalité de journalisation — mais elle ne devient pas un logger. Les traits ajoutent du comportement sans changer ce qu'est fondamentalement la classe.
<?php
// Héritage : Dog EST un Animal
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait : Dog A une capacité de journalisation
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
Différences clés à retenir :
| Aspect | Héritage | Traits |
|---|---|---|
| Relation | est-un (is-a) | possède une capacité (has-a) |
| Limite | Parent unique seulement | Plusieurs traits autorisés |
| Vérification de type | Fonctionne avec instanceof | Pas d'identité de type |
| Idéal pour | Relations hiérarchiques | Comportements partagés entre classes non liées |
Utilisez l'héritage lorsque les classes partagent une identité commune. Utilisez les traits lorsque des classes non liées ont besoin de la même fonctionnalité sans faire partie du même arbre généalogique.
Défi
FacileConstruisons un système de véhicules qui démontre quand utiliser l'héritage par rapport aux traits. Vous allez créer une hiérarchie de véhicules qui partagent une identité commune via l'héritage, tout en ajoutant des capacités transversales via des traits.
Vous organiserez votre code sur quatre fichiers :
Trackable.php— Créez un trait nomméTrackablequi fournit une capacité de suivi GPS. Le trait doit avoir :- Une propriété privée
$location(string) - Une méthode
setLocation(string $location)qui stocke l'emplacement actuel - Une méthode
getLocation()qui retourne"Location: " . $this->location
- Une propriété privée
Vehicle.php— Créez une classe de baseVehiclequi établit la relation de type « est un ». Incluez le fichier du trait. Utilisez la promotion de constructeur pour définir une propriété protégée$brand. Ajoutez une méthodedescribe()qui retourne"Vehicle: " . $this->brand. Cette classe doit utiliser le traitTrackablecar tous les véhicules de notre flotte auront un GPS.Car.php— Créez une classeCarqui étendVehicle. Incluez le fichier Vehicle. Utilisez la promotion de constructeur pour accepter la marque et une propriété privée$doors(integer). Appelez le constructeur parent avec la marque. Surchargez la méthodedescribe()pour retourner"Car: " . $this->brand . " with " . $this->doors . " doors".main.php— Incluez le fichier Car. Vous recevrez trois entrées : un nom de marque, un nombre de portes et une chaîne de caractères pour l'emplacement. Créez une instance deCar, définissez son emplacement, puis affichez deux lignes :- Le résultat de l'appel à
describe() - Le résultat de l'appel à
getLocation()
- Le résultat de l'appel à
Remarquez comment l'héritage et les traits fonctionnent ensemble ici : Car est un Vehicle (l'héritage établit l'identité), tandis que Vehicle possède une capacité de suivi (le trait ajoute un comportement). Vous pourriez utiliser instanceof Vehicle pour vérifier si un objet est un véhicule, mais il n'y a pas de type « Trackable » à vérifier — c'est la différence clé entre ces deux approches.
Aide-mémoire
Utilisez l'héritage pour les relations de type « est un » (is-a) et les traits pour les capacités de type « a une » (has-a).
L'héritage établit une identité : une classe enfant est un type de classe parente et peut être utilisée partout où le type parent est attendu.
Les traits ajoutent un comportement sans changer l'identité de la classe : une classe possède une fonctionnalité mais ne devient pas cette chose.
<?php
// Inheritance: Dog IS an Animal
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait: Cat HAS logging capability
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
| Aspect | Héritage | Traits |
|---|---|---|
| Relation | est un (is-a) | a une capacité (has-a) |
| Limite | Parent unique seulement | Plusieurs traits autorisés |
| Vérification de type | Fonctionne avec instanceof | Pas d'identité de type |
| Idéal pour | Relations hiérarchiques | Comportements partagés entre classes non liées |
Utilisez l'héritage pour les relations hiérarchiques où les classes partagent une identité commune. Utilisez les traits pour les comportements partagés entre des classes non liées.
Essayez vous-même
<?php
// Fichier principal - créer et tester l'instance de Car
// TODO: Inclure le fichier Car.php
// Lire les entrées
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));
// TODO: Créer une instance de Car avec la marque (brand) et les portes (doors)
// TODO: Définir l'emplacement (location) de la voiture
// TODO: Afficher le résultat de describe()
// TODO: Afficher le résultat de getLocation()
?>Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Les bases de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé $thisMéthodesPropriétésConstructeur (__construct)Destructeur (__destruct)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLe mot-clé parent::Redéfinition de méthodeLe mot-clé finalClasses abstraitesRécapitulatif - Hiérarchie des employés7Encapsulation
Public, Protégé, PrivéModificateurs d'accès en détailGetters et SettersMasquage d'informationPromotion de constructeur (8.0)Récapitulatif - Système de gestion d'étudiants10Concepts avancés de la POO
Composition vs HéritageInjection de dépendancesClasses anonymesÉnumérations (PHP 8.1)Fibers (PHP 8.1)Clonage d'objets : analyse approfondieGénérateurs et Itérateurs13Patrons de conception Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode ModèlePatron ÉtatPatron CompositePatron Repository2Espaces de noms et Autoloading
Introduction aux espaces de nomsLe mot-clé useStandard d'Autoloading PSR-4L'Autoloader ComposerRécapitulatif - Projet organisé5Interfaces et Contrats
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesInterface vs Classe AbstraiteType Hinting avec les InterfacesRécapitulatif - Calculateur de Formes8Méthodes magiques
Introduction aux méthodes magiques__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Clonage d'objets__serialize & __unserializeRécapitulatif - Collection personnalisée3Propriétés de classe
Propriétés d'instance vs Propriétés statiquesConstantes dans les classesMéthodes et propriétés statiquesPropriétés privées et protégéesPropriétés readonly (PHP 8.1)Récapitulatif - Gestionnaire de compte bancaire6Polymorphisme
Retour sur la redéfinition de méthodePolymorphisme via les interfacesType Hinting et Types d'unionLiaison statique tardiveRécapitulatif - Processeur de paiement9Traits
Introduction aux TraitsUtilisation de plusieurs TraitsRésolution des conflits de TraitsMéthodes abstraites dans les TraitsTraits vs Héritage12Patrons de conception Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron ObservateurPatron Stratégie