22 Match Expression

Die Match Expression, eingeführt in PHP 8.0, ist eine der bedeutendsten Erweiterungen der Sprachsyntax und stellt eine moderne, leistungsfähige Alternative zur traditionellen switch-Anweisung dar. Dieses neue Sprachmerkmal verbessert die Lesbarkeit, Kompaktheit und Sicherheit des Codes bei der Durchführung von bedingten Vergleichen.

22.1 Grundlegendes Konzept

Die Match Expression führt einen Wert gegen eine Reihe von Bedingungen und gibt das Ergebnis des ersten passenden Arms zurück. Im Gegensatz zur switch-Anweisung ist Match:

22.2 Syntax und Vergleich mit switch

Hier ist ein einfacher Vergleich zwischen der traditionellen switch-Anweisung und der neuen Match Expression:

// Herkömmlicher switch-Ansatz
function getStatusText($status) {
    switch ($status) {
        case 200:
            return 'OK';
        case 404:
            return 'Not Found';
        case 500:
            return 'Internal Server Error';
        default:
            return 'Unknown Status';
    }
}

// Entsprechender Match-Ansatz
function getStatusText($status) {
    return match ($status) {
        200 => 'OK',
        404 => 'Not Found',
        500 => 'Internal Server Error',
        default => 'Unknown Status',
    };
}

Die Match Expression ist deutlich prägnanter und vermeidet typische Fehler, die bei Verwendung von switch auftreten können, wie vergessene break-Anweisungen.

22.3 Wichtige Eigenschaften von Match

22.3.1 1. Strikte Vergleiche

Match verwendet standardmäßig strikte Typvergleiche (===):

$result = match ($value) {
    '1' => 'Zeichenkette 1',
    1 => 'Zahl 1',
    true => 'Boolean true',
    default => 'Nichts hat gepasst'
};

Hier wird nur der Arm ausgeführt, der exakt dem Typ und Wert von $value entspricht.

22.3.2 2. Mehrere Bedingungen pro Arm

Match erlaubt mehrere Bedingungen für jeden Arm, durch Kommas getrennt:

$httpStatus = 418;

$statusMessage = match ($httpStatus) {
    200, 201, 202 => 'Erfolg',
    400, 401, 403, 404 => 'Client-Fehler',
    500, 502, 503 => 'Server-Fehler',
    418 => "I'm a teapot",
    default => 'Unbekannt'
};

echo $statusMessage; // Ausgabe: "I'm a teapot"

22.3.3 3. Ausdrücke als Bedingungen

Match kann Ausdrücke sowohl für den zu vergleichenden Wert als auch für die Ergebnisse verwenden:

$alter = 25;

$altersgruppe = match (true) {
    $alter < 18 => 'Minderjährig',
    $alter >= 18 && $alter < 65 => 'Erwachsen',
    $alter >= 65 => 'Senior',
};

echo $altersgruppe; // Ausgabe: "Erwachsen"

Dieses Muster mit match(true) ist besonders nützlich für Bereichsvergleiche und komplexe Bedingungen.

22.3.4 4. Ausführen von Code in den Arms

Jeder Arm kann komplexe Ausdrücke oder Funktionsaufrufe enthalten:

$ergebnis = match ($wert) {
    1 => berechneEtwas(),
    2 => $this->doOperation($wert),
    3, 4 => function() use ($wert) { return $wert * 2; }(),
    default => throw new Exception("Ungültiger Wert: $wert"),
};

22.3.5 5. Vollständigkeitsprüfung

Match erzwingt die Behandlung aller möglichen Fälle. Wenn keine Übereinstimmung gefunden wird und kein default-Arm vorhanden ist, wird eine UnhandledMatchError-Exception ausgelöst:

$farbe = 'Lila';

try {
    $rgb = match ($farbe) {
        'Rot' => [255, 0, 0],
        'Grün' => [0, 255, 0],
        'Blau' => [0, 0, 255],
    };
} catch (UnhandledMatchError $e) {
    echo "Fehler: Unbekannte Farbe '$farbe'";
}

22.4 Fortgeschrittene Anwendungen

22.4.1 Pattern Matching mit Bedingungen

Eine Stärke von Match ist die Möglichkeit, komplexe Bedingungsmuster zu erstellen:

$ergebnis = match (true) {
    $wert instanceof DateTime => 'Es ist ein Datum',
    is_array($wert) && count($wert) > 0 => 'Nicht-leeres Array',
    is_string($wert) && str_starts_with($wert, 'http') => 'URL',
    is_numeric($wert) && $wert > 0 => 'Positive Zahl',
    default => 'Sonstiger Wert',
};

22.4.2 Validierung und fehlerbasierte Verzweigung

Match eignet sich hervorragend für Validierungsszenarien:

function validateEmail($email) {
    return match (true) {
        $email === '' => 'E-Mail darf nicht leer sein',
        !filter_var($email, FILTER_VALIDATE_EMAIL) => 'Ungültiges E-Mail-Format',
        !checkDomainExists(extractDomain($email)) => 'Domain existiert nicht',
        default => 'valid',
    };
}

$validationResult = validateEmail('test@example.com');

22.4.3 HTTP-Routenbehandlung

Match kann elegante Routenhandler ermöglichen:

$route = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];

$result = match (true) {
    $route === '/users' && $method === 'GET' => getUsersList(),
    $route === '/users' && $method === 'POST' => createUser($_POST),
    $route === '/users/profile' && $method === 'GET' => getUserProfile($_GET['id']),
    default => notFound(),
};

22.4.4 State Machines

Match kann für einfache Zustandsmaschinen verwendet werden:

class OrderStateMachine {
    public function transition(Order $order, string $event) {
        $currentState = $order->getState();
        
        $newState = match ([$currentState, $event]) {
            ['new', 'confirm'] => 'confirmed',
            ['confirmed', 'ship'] => 'shipped',
            ['shipped', 'deliver'] => 'delivered',
            ['confirmed', 'cancel'],
            ['new', 'cancel'] => 'cancelled',
            default => throw new InvalidTransitionException($currentState, $event),
        };
        
        $order->setState($newState);
        return $order;
    }
}

22.5 Best Practices

Bei der Verwendung von Match Expressions sollten einige bewährte Praktiken beachtet werden:

  1. Verwenden Sie Match für Rückgabewerte: Da Match ein Ausdruck ist, eignet es sich besonders gut für Szenarien, in denen ein Wert basierend auf einer Bedingung zurückgegeben werden soll.

  2. Nutzen Sie die Typensicherheit: Der strikte Vergleich von Match führt zu sichererem Code. Nutzen Sie diesen Vorteil bewusst.

  3. Vermeiden Sie übermäßige Komplexität: Obwohl Match sehr ausdrucksstark ist, sollten Sie zu komplexe Bedingungen in separate Funktionen auslagern, um die Lesbarkeit zu bewahren.

  4. Bevorzugen Sie Match gegenüber switch: In den meisten Fällen ist Match die bessere Wahl als switch, da es kompakter, sicherer und ausdrucksstärker ist.

  5. Denken Sie an Performance: Match ist in der Regel effizienter als verschachtelte if-else-Anweisungen, besonders bei vielen Bedingungen.

22.6 Einschränkungen

Match hat einige Einschränkungen, die beachtet werden sollten:

  1. Keine Fall-Through-Mechanismen: Im Gegensatz zu switch bietet Match keine Möglichkeit, Code für mehrere Fälle gemeinsam auszuführen.

  2. Kein Block-Syntax: Match akzeptiert nur einfache Ausdrücke auf der rechten Seite, keine Codeblöcke. Für komplexe Logik müssen Sie Funktionen verwenden.

  3. Keine Dynamischen Keys: Die Bedingungen in Match müssen konstante Ausdrücke sein:

// Dies funktioniert NICHT:
$keys = [1, 2, 3];
$result = match ($value) {
    $keys[0] => 'Fall 1', // Fehler
    // ...
};