In unserem letzten Post haben wir die kommenden Verbesserungen am PHP-Typsystem besprochen. Heute sehen wir uns ein neues Konstrukt an, das die Verzweigungslogik noch leistungsfähiger macht.
PHP hat seit Anbeginn der Zeit eine switch-Anweisung
, die nach dem gleichen Konstrukt in C modelliert ist. Sie haben es sicher schon einmal gesehen:
<?php
switch ($var) {
case 'a':
$message = "The variable was a.";
break;
case 'b':
$message = "The variable was c.";
break;
case 'c':
$message = "The variable was c.";
break;
default:
$message = "The variable was something else.";
break;
}
print $message;
Die klassische switch-Anweisung erfüllt zwar seine Aufgabe, hat aber eine Reihe von Einschränkungen. Die meisten neueren Sprachen wie Go oder Rust haben sich für robustere, weniger fehleranfällige Strukturen entschieden, die auf eine Vielzahl von Namen tragen. Und jetzt hat auch PHP eine.
Hier betritt die PHP-Funktion match
das Spielfeld. Anders als switch
ist PHP match
ein Ausdruck. Das bedeutet, dass er zu einem Wert ausgewertet wird, wie zum Beispiel hier:
<?php
$message = match($var) {
'a' => 'The variable was a',
'b' => 'The variable was b',
'c' => 'The variable was c',
default => 'The variable was something else',
};
print $message;
Hier gibt es mehrere Dinge zu beachten:
switch
wird jeder case
mit loser Gleichheit ==
verglichen. Bei PHP match
wird jeder Zweig mit strikter Gleichheit ===
verglichen. Das bedeutet, dass auch die Typen übereinstimmen müssen.match
ist nur ein einziger Ausdruck. Keine mehrzeiligen Anweisungen, nur ein einziger Ausdruck, der ausgewertet wird. Wenn komplexe Logik benötigt wird, nutzt Funktionen oder Methoden.break
erforderlich ist.match
gibt einen Wert zurück. Das ist der ganze Grund für seine Existenz.;
ganz am Ende erforderlich, genau wie bei closure Definitionen.match
ist anstrengend. Wenn $var
nicht ===
einer der angegebenen Werte ist und es keinen default
gibt, wird ein Fehler ausgelöst.match
-Zweige können auch zusammengesetzt und durch Kommata getrennt werden, um ein "OR"-ähnliches Verhalten zu erreichen, etwa so:
<?php
echo match($operator) {
'+', '-', '*', '/' => 'Basic arithmetic',
'%' => 'Modulus',
'!' => 'Negation',
};
PHP match
wurde als modernisierter, nützlicherer switch
angepriesen, aber ich bin mir nicht sicher, ob das so richtig ist. Ich betrachte match
eher als eine leistungsfähigere ternary-Funktion.
In der Vergangenheit habe ich mich oft in binären Fällen wiedergefunden, in denen eine Variable in Abhängigkeit von einer Bedingung einem von zwei Werten zugewiesen werden kann. Der einfachste Weg, dies zu schreiben, ist folgender:
<?php
$display = $user->isAdmin()
? $user->name() . ' (admin)'
: $user->name() . ' (muggle)'
;
Das ist ein absolut valider Code und ziemlich nützlich. Wenn die Logik in der Bedingung oder in einer der Verzweigungen zu komplex ist, um leicht lesbar zu sein, ist das ein Hinweis darauf, dass die Logik in eine eigene Funktion oder Methode umstrukturiert werden sollte. Ich habe festgestellt, dass dies eine wirklich gute Methodik für Situationen wie diese ist und außerdem zu sehr lesbarem, kompaktem und testbarem Code führt.
Das funktioniert allerdings nur für true
/ false
. match
hingegen funktioniert für eine beliebige Anzahl von Optionen, hat aber denselben Anreiz, Sie zu gut fundiertem, sauberem Code zu bewegen.
Wenn komplexere Bedingungen als die einfache Identität benötigt wird, können Sie match
auf true
anwenden:
<?php
$count = get_count();
$size = match(true) {
$count > 0 && $count <=10 => 'small',
$count <=50 => 'medium',
$count >50 => 'huge',
};
Da es keinen default
gibt, führt eine Nichtübereinstimmung (in diesem Fall, wenn $count
0 oder negativ ist) zu einem Fehler, anstatt dass eine Zuweisung zu null erfolgt und weitergemacht wird. Das ist gut, denn so können sich Fehler nicht ausbreiten und späteren Code verunreinigen.
Der Match Expression RFC wurde uns freundlicherweise von Ilija Tovilo zur Verfügung gestellt.