Traits vs. Vererbung
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 55 von 91.
Nachdem Sie nun verstehen, wie Traits funktionieren, lassen Sie uns klären, wann Traits im Gegensatz zur Vererbung verwendet werden sollten. Beide ermöglichen die Wiederverwendung von Code, aber sie dienen unterschiedlichen Zwecken und haben unterschiedliche Merkmale.
Vererbung stellt eine „ist-ein“-Beziehung her. Eine Dog-Klasse, die Animal erweitert, bedeutet, dass ein Hund ein Tier ist. Die Kindklasse erbt die Identität der Elternklasse und kann überall dort verwendet werden, wo der Typ der Elternklasse erwartet wird.
Traits bieten eine „has-a“-Fähigkeit. Wenn eine Klasse ein Loggable-Trait verwendet, besitzt sie Logging-Funktionalität – aber sie wird nicht zu einem Logger. Traits fügen Verhalten hinzu, ohne das grundlegende Wesen der Klasse zu verändern.
<?php
// Vererbung: Hund IST ein Tier
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait: Hund HAT Protokollierungsfunktionen
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
Wichtige Unterschiede, die man sich merken sollte:
| Aspekt | Vererbung | Traits |
|---|---|---|
| Beziehung | is-a | has-a capability |
| Einschränkung | Nur ein Elternteil | Mehrere Traits erlaubt |
| Typprüfung | Funktioniert mit instanceof | Keine Typidentität |
| Bestens geeignet für | Hierarchische Beziehungen | Gemeinsame Verhaltensweisen über nicht verwandte Klassen hinweg |
Verwenden Sie Vererbung, wenn Klassen eine gemeinsame Identität teilen. Verwenden Sie Traits, wenn nicht verwandte Klassen dieselbe Funktionalität benötigen, ohne Teil desselben Stammbaums zu sein.
Aufgabe
EinfachLassen Sie uns ein Fahrzeugsystem bauen, das demonstriert, wann Vererbung gegenüber Traits verwendet werden sollte. Sie werden eine Hierarchie von Fahrzeugen erstellen, die durch Vererbung eine gemeinsame Identität teilen, während Sie durch Traits querschnittliche Funktionen hinzufügen.
Sie werden Ihren Code über vier Dateien organisieren:
Trackable.php— Erstellen Sie einen Trait namensTrackable, der GPS-Tracking-Funktionen bereitstellt. Der Trait sollte Folgendes haben:- Eine private Eigenschaft
$location(string) - Eine Methode
setLocation(string $location), die den aktuellen Standort speichert - Eine Methode
getLocation(), die"Location: " . $this->locationzurückgibt
- Eine private Eigenschaft
Vehicle.php— Erstellen Sie eine BasisklasseVehicle, die die "ist-ein"-Beziehung herstellt. Binden Sie die Trait-Datei ein. Verwenden Sie Constructor Promotion, um eine geschützte Eigenschaft$brandzu definieren. Fügen Sie eine Methodedescribe()hinzu, die"Vehicle: " . $this->brandzurückgibt. Diese Klasse sollte denTrackableTrait verwenden, da alle Fahrzeuge in unserer Flotte über GPS verfügen werden.Car.php— Erstellen Sie eine KlasseCar, dieVehicleerweitert. Binden Sie die Vehicle-Datei ein. Verwenden Sie Constructor Promotion, um die Marke und eine private Eigenschaft$doors(integer) zu akzeptieren. Rufen Sie den Eltern-Konstruktor mit der Marke auf. Überschreiben Sie die Methodedescribe(), sodass sie"Car: " . $this->brand . " with " . $this->doors . " doors"zurückgibt.main.php— Binden Sie die Car-Datei ein. Sie erhalten drei Eingaben: einen Markennamen, eine Anzahl von Türen und einen Standort-String. Erstellen Sie eineCar-Instanz, setzen Sie deren Standort und geben Sie dann zwei Zeilen aus:- Das Ergebnis des Aufrufs von
describe() - Das Ergebnis des Aufrufs von
getLocation()
- Das Ergebnis des Aufrufs von
Beachten Sie, wie Vererbung und Traits hier zusammenarbeiten: Car ist ein Vehicle (Vererbung stellt die Identität her), während Vehicle eine Tracking-Funktion hat (der Trait fügt Verhalten hinzu). Sie könnten instanceof Vehicle verwenden, um zu prüfen, ob etwas ein Fahrzeug ist, aber es gibt keinen "Trackable"-Typ, gegen den man prüfen könnte — das ist der entscheidende Unterschied zwischen diesen beiden Ansätzen.
Spickzettel
Verwenden Sie Vererbung für „is-a“-Beziehungen und Traits für „has-a“-Fähigkeiten.
Vererbung stellt Identität her – eine Kindklasse ist ein Typ der Elternklasse und kann überall dort verwendet werden, wo der Elterntyp erwartet wird.
Traits fügen Verhalten hinzu, ohne die Klassenidentität zu ändern – eine Klasse hat eine Funktionalität, wird aber nicht zu diesem Ding.
<?php
// Vererbung: Dog IST ein Animal
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait: Cat HAT Logging-Fähigkeit
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
| Aspekt | Vererbung | Traits |
|---|---|---|
| Beziehung | is-a | has-a capability |
| Einschränkung | Nur ein Elternteil | Mehrere Traits erlaubt |
| Typprüfung | Funktioniert mit instanceof | Keine Typidentität |
| Bestens geeignet für | Hierarchische Beziehungen | Gemeinsame Verhaltensweisen über nicht verwandte Klassen hinweg |
Verwenden Sie Vererbung für hierarchische Beziehungen, bei denen Klassen eine gemeinsame Identität teilen. Verwenden Sie Traits für gemeinsame Verhaltensweisen über nicht verwandte Klassen hinweg.
Probier es selbst
<?php
// Hauptdatei - Erstellen und Testen der Car-Instanz
// TODO: Die Datei Car.php einbinden
// Eingaben lesen
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));
// TODO: Eine Car-Instanz mit Marke und Türen erstellen
// TODO: Den Standort des Autos festlegen
// TODO: Das Ergebnis von describe() ausgeben
// TODO: Das Ergebnis von getLocation() ausgeben
?>Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas $this-SchlüsselwortMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick - Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDas parent:: SchlüsselwortMethoden überschreibenDas final SchlüsselwortAbstrakte KlassenZusammenfassung – Mitarbeiter-Hierarchie7Kapselung
Public, Protected, PrivateZugriffsmodifikatoren im DetailGetter und SetterInformation HidingConstructor Promotion (8.0)Zusammenfassung – Studentenverwaltungssystem2Namensräume & Autoloading
Einführung in NamensräumeDas use-SchlüsselwortPSR-4 Autoloading-StandardComposer AutoloaderZusammenfassung – Organisiertes Projekt5Interfaces & Verträge
Einführung in InterfacesInterfaces implementierenMehrfache Interface-ImplementierungInterface vs. Abstrakte KlasseType Hinting mit InterfacesZusammenfassung – Formen-Rechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objekt-Klonen__serialize & __unserializeZusammenfassung - Eigene Collection11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenEigene Exception-HierarchieTry, Catch, FinallyZusammenfassung - Formular-Validator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klasseneigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenReadonly-Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphismus
Method Overriding erneut betrachtetPolymorphismus über InterfacesType Hinting & Union TypesLate Static BindingZusammenfassung – Payment Processor9Traits
Einführung in TraitsVerwendung mehrerer TraitsKonfliktlösung bei TraitsAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung