Menu
Coddy logo textTech

Eigene Exception-Hierarchie

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

Während PHPs integrierte Exception-Klassen gängige Szenarien abdecken, benötigen reale Anwendungen oft spezifischere Fehlertypen. Das Erstellen einer benutzerdefinierten Exception-Hierarchie ermöglicht es Ihnen, Exceptions zu definieren, die zu Ihrer Domäne passen, und sie auf verschiedenen Ebenen der Spezifität abzufangen.

Um eine benutzerdefinierte Exception zu erstellen, erweitern Sie einfach die Exception-Klasse oder eine ihrer Unterklassen:

<?php
class PaymentException extends Exception {}

class InsufficientFundsException extends PaymentException {
    public function __construct(
        private float $required,
        private float $available
    ) {
        parent::__construct("Need $required but only $available available");
    }
    
    public function getShortfall(): float {
        return $this->required - $this->available;
    }
}

Beachten Sie, wie InsufficientFundsException PaymentException erweitert und nicht direkt Exception. Dies erzeugt eine Hierarchie, in der Sie alle zahlungsbezogenen Ausnahmen mit einem catch-Block abfangen oder spezifische einzeln behandeln können.

Benutzerdefinierte Exceptions können zusätzliche Eigenschaften und Methoden enthalten, die für den Fehler relevant sind. Hier bietet getShortfall() nützliche Informationen, die eine generische Exception nicht bieten könnte:

<?php
class Wallet {
    public function __construct(private float $balance) {}
    
    public function pay(float $amount): void {
        if ($amount > $this->balance) {
            throw new InsufficientFundsException($amount, $this->balance);
        }
        $this->balance -= $amount;
    }
}

Eine gut entworfene Ausnahmehierarchie macht Ihren Code wartbarer. Beim Abfangen von Ausnahmen können Sie so allgemein oder spezifisch wie nötig vorgehen, und die Ausnahmeobjekte selbst enthalten aussagekräftigen Kontext darüber, was schiefgelaufen ist.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Auftragsverarbeitungssystem mit einer benutzerdefinierten Ausnahmehierarchie aufbauen, die verschiedene Arten von Auftragsfehlern behandelt. Sie werden Ausnahmen erstellen, die einen aussagekräftigen Kontext darüber enthalten, was schiefgelaufen ist, wodurch die Fehlerbehandlung präziser und informativer wird.

Sie werden Ihren Code über vier Dateien organisieren:

  • OrderException.php — Erstellen Sie eine Basisklasse OrderException, die Exception erweitert. Diese dient als Elternklasse für alle auftragsbezogenen Ausnahmen und ermöglicht es Ihnen, bei Bedarf jedes Auftragsproblem mit einem einzigen Catch-Block abzufangen.
  • OutOfStockException.php — Erstellen Sie eine Klasse OutOfStockException, die OrderException erweitert. Diese Ausnahme sollte einen Produktnamen und die angeforderte Menge in ihrem Konstruktor akzeptieren. Verwenden Sie Constructor Promotion für diese privaten Eigenschaften. Rufen Sie den Eltern-Konstruktor mit einer Nachricht im Format "[productName] is out of stock (requested: [quantity])" auf. Fügen Sie eine Methode getProductName(): string hinzu, die den Produktnamen zurückgibt.
  • InvalidQuantityException.php — Erstellen Sie eine Klasse InvalidQuantityException, die OrderException erweitert. Diese Ausnahme sollte einen Mengenwert in ihrem Konstruktor mittels Constructor Promotion als private Eigenschaft akzeptieren. Rufen Sie den Eltern-Konstruktor mit der Nachricht "Invalid quantity: [quantity]" auf. Fügen Sie eine Methode getQuantity(): int hinzu, die den Mengenwert zurückgibt.
  • main.php — Binden Sie alle drei Ausnahmedateien ein. Sie erhalten zwei Eingaben: einen Produktnamen und eine Menge (als String, der in einen Integer umgewandelt werden muss).

    Werfen Sie basierend auf dem Mengenwert die entsprechende Ausnahme:

    • Wenn die Menge kleiner als 1 ist, werfen Sie eine InvalidQuantityException
    • Wenn die Menge größer als 100 ist, werfen Sie eine OutOfStockException (um unzureichenden Lagerbestand zu simulieren)
    • Andernfalls geben Sie "Order placed: [quantity]x [productName]" aus

    Fangen Sie Ausnahmen mithilfe der Hierarchie ab. Fangen Sie zuerst InvalidQuantityException ab und geben Sie "Quantity error: [message] (value: [quantity])" unter Verwendung der Nachricht der Ausnahme und der Methode getQuantity() aus. Fangen Sie dann OutOfStockException ab und geben Sie "Stock error: [message] (product: [productName])" unter Verwendung der Nachricht der Ausnahme und der Methode getProductName() aus.

Diese Hierarchie ermöglicht es Ihnen, spezifische Ausnahmen einzeln zu behandeln, während Sie dennoch die Option haben, alle auftragsbezogenen Probleme über die Basisklasse OrderException abzufangen. Die benutzerdefinierten Methoden jeder Ausnahme bieten einen Kontext, den eine generische Ausnahme nicht bieten könnte.

Spickzettel

Erstellen Sie benutzerdefinierte Exceptions, indem Sie die Klasse Exception oder deren Unterklassen erweitern:

<?php
class PaymentException extends Exception {}

class InsufficientFundsException extends PaymentException {
    public function __construct(
        private float $required,
        private float $available
    ) {
        parent::__construct("Need $required but only $available available");
    }
    
    public function getShortfall(): float {
        return $this->required - $this->available;
    }
}

Benutzerdefinierte Exceptions können eine Hierarchie bilden, indem sie andere benutzerdefinierte Exceptions erweitern. Dies ermöglicht das Abfangen von Exceptions auf verschiedenen Spezifitätsebenen – fangen Sie alle zahlungsbezogenen Exceptions mit PaymentException ab oder behandeln Sie spezifische wie InsufficientFundsException einzeln.

Benutzerdefinierte Exceptions können zusätzliche Eigenschaften und Methoden enthalten, um Kontext zum Fehler bereitzustellen:

<?php
class Wallet {
    public function __construct(private float $balance) {}
    
    public function pay(float $amount): void {
        if ($amount > $this->balance) {
            throw new InsufficientFundsException($amount, $this->balance);
        }
        $this->balance -= $amount;
    }
}

Verwenden Sie Constructor Promotion, um Eigenschaften direkt in den Konstruktor-Parametern zu definieren. Rufen Sie parent::__construct() auf, um die Exception-Nachricht festzulegen.

Probier es selbst

<?php
// Alle Exception-Dateien einbinden
require_once 'OrderException.php';
require_once 'OutOfStockException.php';
require_once 'InvalidQuantityException.php';

// Eingabe lesen
$productName = trim(fgets(STDIN));
$quantity = intval(trim(fgets(STDIN)));

// TODO: try-catch verwenden, um die Bestellabwicklung zu handhaben
// Innerhalb des try-Blocks:
//   - Wenn quantity < 1, InvalidQuantityException werfen
//   - Wenn quantity > 100, OutOfStockException werfen
//   - Andernfalls "Order placed: [quantity]x [productName]" ausgeben
//
// Zuerst InvalidQuantityException abfangen:
//   - "Quantity error: [message] (value: [quantity])" mit getMessage() und getQuantity() ausgeben
//
// OutOfStockException abfangen:
//   - "Stock error: [message] (product: [productName])" mit getMessage() und getProductName() ausgeben

?>
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