Menu
Coddy logo textTech

Abstrakte Methoden in Traits

Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 54 von 91.

Traits können gebrauchsfertige Methoden bereitstellen, aber manchmal müssen die Klassen, die den Trait verwenden, eine spezifische Funktionalität implementieren. Hier werden abstrakte Methoden in Traits nützlich – sie definieren einen Vertrag, den die verwendende Klasse erfüllen muss.

Wenn ein Trait eine abstrakte Methode deklariert, muss jede Klasse, die diesen Trait verwendet, diese implementieren:

<?php
trait Notifiable {
    abstract public function getEmail(): string;
    
    public function sendNotification(string $message): void {
        echo "Sending to " . $this->getEmail() . ": $message";
    }
}

class User {
    use Notifiable;
    
    public function __construct(private string $email) {}
    
    public function getEmail(): string {
        return $this->email;
    }
}

$user = new User("john@example.com");
$user->sendNotification("Welcome!");

Ausgabe:

Sending to john@example.com: Welcome!

Der Trait stellt die Methode sendNotification() bereit, verlässt sich jedoch darauf, dass getEmail() von der Klasse implementiert wird. Dies schafft ein leistungsfähiges Muster, bei dem der Trait die allgemeine Logik übernimmt, während klassenspezifische Details an die implementierende Klasse delegiert werden.

Wenn eine Klasse den Trait verwendet, ohne die abstrakte Methode zu implementieren, wirft PHP einen fatalen Fehler. Dies stellt sicher, dass Traits sicher darauf vertrauen können, dass bestimmte Methoden existieren, was Ihren Code vorhersehbarer und wartbarer macht.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Preissystem aufbauen, bei dem verschiedene Produkttypen ihre Endpreise unterschiedlich berechnen, aber alle eine gemeinsame Rabattlogik über ein Trait mit einer abstrakten Methode teilen.

Sie werden Ihren Code über drei Dateien organisieren:

  • Discountable.php — Erstellen Sie ein Trait namens Discountable, das Rabattfunktionen bereitstellt. Das Trait sollte Folgendes enthalten:
    • Eine abstrakte Methode getBasePrice(): float, die Klassen, die dieses Trait verwenden, implementieren müssen
    • Eine Methode applyDiscount(int $percent), die den Preis nach Anwendung des Rabattprozentsatzes auf den Basispreis berechnet und zurückgibt
    • Eine Methode getFinalPrice(int $percent), die einen formatierten String zurückgibt: "Final price: $[discounted_price]" mit 2 Dezimalstellen
    Das Trait übernimmt die gesamte Rabattberechnung, verlässt sich jedoch darauf, dass jede Klasse ihm mitteilt, wie hoch der Basispreis ist.
  • Product.php — Erstellen Sie eine Product-Klasse, die das Discountable-Trait verwendet. Binden Sie die Trait-Datei ein. Verwenden Sie Constructor Promotion, um ein privates $name (string) und ein privates $price (float) zu definieren. Implementieren Sie die erforderliche Methode getBasePrice(), um den Preis des Produkts zurückzugeben.
  • main.php — Binden Sie die Product-Datei ein. Sie erhalten drei Eingaben: einen Produktnamen, einen Preis und einen Rabattprozentsatz. Erstellen Sie eine Product-Instanz und geben Sie zwei Zeilen aus:
    • Den Basispreis, formatiert als "Base: $[price]" mit 2 Dezimalstellen
    • Das Ergebnis des Aufrufs von getFinalPrice() mit dem Rabattprozentsatz

Dieses Muster ist leistungsstark, da das Discountable-Trait von jeder Klasse verwendet werden kann — Produkten, Dienstleistungen, Abonnements —, solange diese getBasePrice() implementieren. Das Trait liefert die gemeinsame Rabattlogik, während jede Klasse definiert, woher ihr Basispreis stammt.

Spickzettel

Traits können abstrakte Methoden deklarieren, die von jeder Klasse, die den Trait verwendet, implementiert werden müssen:

<?php
trait Notifiable {
    abstract public function getEmail(): string;
    
    public function sendNotification(string $message): void {
        echo "Sending to " . $this->getEmail() . ": $message";
    }
}

class User {
    use Notifiable;
    
    public function __construct(private string $email) {}
    
    public function getEmail(): string {
        return $this->email;
    }
}

Der Trait stellt gebrauchsfertige Methoden zur Verfügung, während er von der Klasse verlangt, eine spezifische Funktionalität zu implementieren. Wenn eine Klasse den Trait verwendet, ohne die abstrakte Methode zu implementieren, wirft PHP einen fatalen Fehler.

Dieses Muster ermöglicht es Traits, allgemeine Logik zu verarbeiten, während klassenspezifische Details an die implementierende Klasse delegiert werden.

Probier es selbst

<?php

require_once 'Product.php';

// Eingaben lesen
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$discountPercent = intval(trim(fgets(STDIN)));

// TODO: Erstellen Sie eine Product-Instanz mit dem Namen und dem Preis

// TODO: Geben Sie den Basispreis im Format "Base: $[price]" mit 2 Dezimalstellen aus

// TODO: Geben Sie das Ergebnis des Aufrufs von getFinalPrice() mit dem Rabattprozentsatz aus

?>
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung