Entwickler, der außergewöhnliche CRM- und Laravel-Lösungen liefert

Als erfahrener Entwickler spezialisiere ich mich auf Laravel- und Vue.js-Entwicklung, die Implementierung von Vtiger CRM sowie auf vielfältige WordPress-Projekte. Meine Arbeit zeichnet sich durch kreative, dynamische und benutzerzentrierte Weblösungen aus, die individuell an die Bedürfnisse meiner Kunden angepasst werden.

Über Möglichkeiten der Fehlerrückgabe in PHP

Während der Ausführung einer Funktion entsteht oft die Notwendigkeit, einen Fehler zu behandeln und die Ausführung der Funktion abzubrechen. Schauen wir uns an, wie man das in PHP umsetzen kann 🤓

Eine Funktion kann also entweder einen Fehler oder bestimmte Daten zurückgeben. In unserem Beispiel sind die Daten eine ganze Zahl (Integer) und der Fehler ein String.

⭐️ Variante 1: Exceptions (Ausnahmen)

Im Fehlerfall werfen wir eine Exception.

final class MyException extends Exception {}

/**
 * @throws MyException
 */
function calc(): int
{
    return 42; // Erfolg
    throw new MyException('Ungültig!'); // Fehler
}

try {
    $data = calc();
    echo sprintf('Ergebnis: %d', $data);
} catch (MyException $e) {
    echo sprintf('Fehler: %s', $e->getMessage());
}

Wenn ein Fehler ein erwartetes Verhalten ist, handelt es sich nicht um eine Ausnahmesituation, und die Verwendung von Exceptions ist hier inkorrekt: Der Code wird komplizierter, man könnte vergessen, Exceptions zu behandeln, usw.


⭐️ Variante 2: Tupel

/**
 * @return list{null, string}|list{int, null}
 */
function calc(): array
{
    return [42, null]; // Erfolg
    return [null, 'Ungültig!']; // Fehler
}

[$data, $error] = calc();
if ($error === null) {
    echo sprintf('Ergebnis: %d', $data);
} else {
    echo sprintf('Fehler: %s', $error);
}

Diese Variante ist schon besser, aber die Verwendung eines Arrays ist nicht sehr komfortabel: komplexe Typ-Annotation und wenig semantischer Code.


⭐️ Variante 3: Union Types (Vereinigungstypen)

Realisierbar für Fälle, in denen sich die Typen von Fehler und Ergebnis unterscheiden.

function calc(): int|string
{
    return 42; // Erfolg
    return 'Ungültig!'; // Fehler
}

$result = calc();
if (is_int($result)) {
    echo sprintf('Ergebnis: %d', $result);
} else {
    echo sprintf('Fehler: %s', $result);
}

Diese Variante ist nicht immer geeignet, sieht äußerst unsemantisch aus und ist schlecht lesbar.


⭐️ Variante 4: Das Ergebnis-Objekt (Result Object)

Das Ergebnis-Objekt enthält den Fehler oder die Daten sowie eine Methode zur Überprüfung des Erfolgs. Beispiel einer Implementierung:

/**
 * @template-covariant TResult
 * @template-covariant TError
 */
final readonly class Result
{
    /**
     * @param TResult|TError $data
     */
    private function __construct(public mixed $data, private bool $isSuccess) {}

    /**
     * @template T
     * @param T $data
     * @return self<T, never>
     */
    public static function success(mixed $data): self
    {
        /** @var self<T, never> */
        return new self($data, true);
    }

    /**
     * @template T
     * @param T $error
     * @return self<never, T>
     */
    public static function error(mixed $error): self
    {
        /** @var self<never, T> */
        return new self($error, false);
    }

    /**
     * @phpstan-assert-if-true TResult $this->data
     * @phpstan-assert-if-false TError $this->data
     */
    public function isSuccess(): bool
    {
        return $this->isSuccess;
    }
}

Beispiel für die Verwendung:

/**
 * @return Result<int, string>
 */
function calc(): Result
{
    return Result::success(42); // Erfolg
    return Result::error('Ungültig!'); // Fehler
}

$result = calc();
if ($result->isSuccess()) {
    echo sprintf('Ergebnis: %d', $result->data);
} else {
    echo sprintf('Fehler: %s', $result->data);
}

Meiner Meinung nach ist dies die beste Variante:

  • Das Objekt wird einmal geschrieben und kann anschließend im gesamten Projekt wiederverwendet werden.
  • Der Code ist einfach und lesbar.
  • Die Fehlerbehandlung wird explizit an den aufrufenden Code delegiert.
  • PHPStan versteht die Typen (für Psalm konnte dies nicht realisiert werden).
  • PhpStorm zeigt korrekte Autovervollständigungen und Hinweise an.