mitmario.dev

switch, und warum match meistens gewinnt

PHP Sandbox 3 Min Lesezeit 4 BeispieleLektion 3 von 7

switch gibt es in PHP seit den Neunzigern, und es steht in praktisch jedem Projekt, das älter ist als PHP 8. Diese Lektion hat deshalb ein anderes Ziel als die übrigen: Du sollst switch lesen können. Schreiben wirst du danach lieber match, und am Ende steht, warum.

Der Aufbau

Ein switch von oben nach unten
<?php

$tag = "Sa";

switch ($tag) {
    case "Mo":
    case "Di":
    case "Mi":
    case "Do":
    case "Fr":
        echo "Arbeitstag\n";
        break;
    case "Sa":
    case "So":
        echo "Wochenende\n";
        break;
    default:
        echo "kein gueltiger Tag\n";
}

Ein switch bekommt einen Wert in runde Klammern und danach einen Block mit case-Marken. PHP sucht die erste Marke, die zum Wert passt, springt dorthin und führt ab da alles aus, bis ein break kommt. Trifft keine Marke, springt es zu default, falls es eines gibt.

Der letzte Satz ist der ganze Unterschied zu allem, was du bisher kennst. Ein case ist keine Schublade, sondern ein Einsprungpunkt. Was danach kommt, läuft mit, auch wenn es zu einer anderen Marke gehört.

Im Beispiel wird das ausgenutzt: Die fünf Werktage stehen als fünf leere case-Zeilen untereinander, und erst hinter dem letzten steht Code. Wer bei Mo einsteigt, fällt durch bis zu dem echo hinter Fr. So sieht in switch ein Sammelzweig aus, für den match ein einziges Komma braucht.

Das vergessene break

Das vergessene break
<?php

$stufe = 2;

switch ($stufe) {
    case 1:
        $text = "klein";
        break;
    case 2:
        $text = "mittel";
        // Hier fehlt das break mit Absicht.
    case 3:
        $text = "gross";
        break;
    default:
        $text = "unbekannt";
}

echo "Stufe $stufe ergibt: $text\n";

Und jetzt dieselbe Eigenschaft von ihrer schlechten Seite. Im zweiten Beispiel fehlt hinter case 2 das break. Die Ausgabe lautet deshalb nicht mittel, sondern gross: PHP springt bei case 2 hinein, setzt $text auf mittel, läuft weiter in case 3 hinein, überschreibt $text mit gross und hört erst am nächsten break auf.

Es gibt keine Warnung dazu. Kein Hinweis auf dem Fehlerkanal, und php index.php; echo $? im Terminal meldet eine 0, als wäre alles in Ordnung. Nur ein falscher Wert, der aussieht wie ein richtiger. Das ist die teuerste Sorte Fehler, und es ist der Grund, warum ein vergessenes break sprichwörtlich ist.

Sehen kannst du das Durchfallen trotzdem, im Reiter Debug. Nach Aufzeichnen stehen dort die Zeilen in der Reihenfolge, in der sie gelaufen sind: erst $text = "mittel";, direkt darunter $text = "gross"; mit dem Chip text="mittel" daneben, und erst am break steht text="gross". Die Ausgabe zeigt dir nur das Ergebnis, die Liste zeigt dir den Weg dorthin.

Ein Trost bleibt: Der letzte Zweig braucht keines. Trotzdem schreibt man es traditionell auch dort hin, damit ein später angehängter Fall nicht plötzlich mitläuft.

Zwei Gleichheitszeichen, wieder einmal

switch vergleicht mit zwei Gleichheitszeichen
<?php

$eingabe = "1";

switch ($eingabe) {
    case 1:
        echo "Der Text 1 trifft die Zahl 1\n";
        break;
    default:
        echo "kein Treffer\n";
}

$null = 0;

switch ($null) {
    case "abc":
        echo "Die Null trifft den Text abc\n";
        break;
    default:
        echo "Die Null trifft den Text abc nicht mehr\n";
}

switch vergleicht mit ==, nicht mit ===. Damit gelten hier genau die Regeln aus Lektion 3.6, und du kannst sie nicht abschalten: Im Beispiel trifft der Text "1" die Marke case 1.

Der zweite Teil zeigt, was PHP 8 daran aufgeräumt hat. Früher traf die Zahl 0 jeden Text, der sich nicht als Zahl lesen ließ, case "abc" eingeschlossen. Heute nicht mehr, und das war eine der besten Änderungen der Version. Der Rest der Liste aus 3.6 gilt aber weiter, "10" und "1e1" zum Beispiel sind mit == nach wie vor dasselbe.

match hat dieses Problem nicht, weil es mit === vergleicht. Es ist der einzige der beiden, bei dem du dir über die Sorte des Wertes keine Gedanken machen musst.

Beide nebeneinander

Dieselbe Entscheidung zweimal geschrieben
<?php

$rolle = "redakteur";

switch ($rolle) {
    case "admin":
        $rechte = "alles";
        break;
    case "redakteur":
        $rechte = "schreiben";
        break;
    default:
        $rechte = "lesen";
}

echo "switch: $rechte\n";

$rechte = match ($rolle) {
    "admin" => "alles",
    "redakteur" => "schreiben",
    default => "lesen",
};

echo "match:  $rechte\n";

Dieselbe Zuordnung, einmal in jeder Form. Der switch braucht zehn Zeilen, das match fünf, und drei Unterschiede sind dabei mehr als Geschmack:

  • match liefert einen Wert. Beim switch musst du in jedem Zweig einer Variablen etwas zuweisen und hoffen, dass du keinen vergisst. Vergisst du einen, ist die Variable danach gar nicht gesetzt, und du bekommst eine Warnung an einer ganz anderen Stelle.
  • match kennt kein Durchfallen. Es gibt kein break, das man vergessen könnte.
  • match beschwert sich, wenn nichts passt. Der switch läuft in dem Fall stillschweigend weiter, als wäre nichts gewesen.

Deshalb die Regel für diesen Kurs: match schreiben, switch lesen können. Und wenn du in einem alten Projekt einen switch vor dir hast, dessen Ergebnis nicht stimmt, ist die erste Frage immer dieselbe: Wo fehlt das break?

Zum Mitnehmen

switch ist der ältere Bruder von match. Du wirst ihn in jedem fremden PHP-Projekt finden, also musst du ihn lesen können. Selbst schreiben wirst du ihn nach dieser Lektion vermutlich nicht mehr, und das hat drei sehr konkrete Gründe.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.