- PHP 8: match or switch?
- # No type coercion
- # Unknown values cause errors
- # Only single-line expressions, for now
- # Combining conditions
- # Complex conditions and performance
- # Throwing exceptions
- # Pattern matching
- # So, switch or match?
- Как использовать выражение match в PHP и чем оно отличается от switch
- Возврат значения
- Множественные условия
- Однострочные выражения
- Отсутствие оператора break
- Шаблон default
- Отсутствие совпадений
- Исключение UnhandledMatchError
- Строгое сравнение без приведения типов
- Сравнение с произвольными выражениями
- Чем различаются match и switch
- С какими версиями PHP совместим match
- Что выбрать: match или switch
PHP 8: match or switch?
PHP 8 introduces the new match expression. A powerful feature that will often be the better choice to using switch . So what exactly are the differences?
Let’s start by comparing the two. Here’s a classic switch example:
switch ($statusCode) < case 200: case 300: $message = null; break; case 400: $message = 'not found'; break; case 500: $message = 'server error'; break; default: $message = 'unknown status code'; break; >
Here’s its match equivalent:
$message = match ($statusCode) < 200, 300 => null, 400 => 'not found', 500 => 'server error', default => 'unknown status code', >;
First of all, the match expression is significantly shorter:
- it doesn’t require a break statement
- it can combine different arms into one using a comma
- it returns a value, so you only have to assign value once
That’s already quite a lot, but there’s even more to it!
# No type coercion
match will do strict type checks instead of loose ones. It’s like using === instead of == . People will probably disagree whether that’s a good thing or not, but that’s a topic on its own.
$statusCode = '200'; $message = match ($statusCode) < 200 => null, default => 'unknown status code', >; // $message = 'unknown status code'
Noticed a tpyo? You can submit a PR to fix it. If you want to stay up to date about what’s happening on this blog, you can follow me on Twitter or subscribe to my newsletter:
# Unknown values cause errors
If you forget to check for a value, and when there’s no default arm specified, PHP will throw an UnhandledMatchError exception. Again more strictness, but it will prevent subtle bugs from going unnoticed.
$statusCode = 400; $message = match ($statusCode) < 200 => 'perfect', >; // UnhandledMatchError
# Only single-line expressions, for now
Just like short closures, you can only write one expression. Expression blocks will probably get added at one point, but it’s still not clear when exactly.
# Combining conditions
You already noticed the lack of break ? This also means match doesn’t allow for fallthrough conditions, like the two combined case lines in the first switch example. On the other hand though, you can combine conditions on the same line, separated by commas.
So you have the same functionality as switch in this regards, but with less writing, and less ways to screw up. Win-win!
$message = match ($statusCode) < 200, 300, 301, 302 => 'combined expressions', >;
# Complex conditions and performance
During the RFC discussion, some people suggested the following pattern as an argument against adding the match expression:
$message = [ $this->matchesRegex($line) => 'match A', $this->matchesOtherRegex($line) => 'match B', ][$line] ?? 'no match';
There’s one big caveat though: this technique will execute all regex functions first, decreasing performance. A good argument for match .
# Throwing exceptions
Finally, because of throw expressions in PHP 8, it’s also possible to directly throw from an arm, if you’d like to.
$message = match ($statusCode) < 200 => null, 500 => throw new ServerError(), default => 'unknown status code', >;
# Pattern matching
Ok, there’s one more thing: pattern matching. It’s a technique used in other programming languages, to allow complexer matching than simple values. Think of it as regex, but for variables instead of text.
Pattern matching isn’t supported right now, because it’s quite a complex feature, but Ilija Tovilo, the RFC author did mention it as a possible future feature. Something to look out for!
Interface Default Methods
# So, switch or match?
If I’d need to summarise the match expression in one sentence, I’d say it’s the stricter and more modern version of it’s little switch brother.
There are some cases — see what I did there? — where switch will offer more flexibility, especially with multiline code blocks. However, the strictness of the match operator is appealing, and the perspective of pattern matching would be a game-changer for PHP.
I admit I never wrote a switch statement in the past years because of its many quirks; quirks that match actually solve. So while it’s not perfect yet, there are use cases that I can think of, where match would be a good… match.
Как использовать выражение match в PHP и чем оно отличается от switch
Выражение match разветвляет поток исполнения кода в PHP. Но практически тем же занимается и оператор switch . Разбираемся, чем они отличаются друг от друга и в каких случаях лучше применять именно match .
Эта статья больше подходит для тех, кто уже немного знает основы PHP. Если вы еще не разобрались с ним, советуем перед прочтением пройти большую профессию по PHP на Хекслете.
Выражение match разветвляет поток исполнения кода через проверку совпадения значения с заданным условием. Как и оператор switch , match принимает на вход выражение, которое сравнивается с множеством альтернатив. Только в отличие от switch , оно возвращает значение, похожее на тернарный оператор.
Выражение match появилось в восьмой версии PHP. Оно выполняет практически те же задачи, что и switch , но имеет ряд преимуществ.
Рассмотрим пример использования выражения match :
$subject = 'two'; echo match ($subject) 'one' => 'foo', 'two' => 'bar', 'three' => 'baz', default => 'default', >; // => bar
Если заменить в этом примере match на блок switch , код будет длиннее:
$subject = 'two'; switch ($subject) case 'one': $result = 'foo'; break; case 'two': $result = 'bar'; break; case 'three': $result = 'baz'; break; default: $result = 'default'; break; > echo $result; // => bar
Давайте более подробно поговорим о том, как работает выражение match .
Возврат значения
В отличие от switch , выражение match возвращает результат — возвращаемое значение каждой ветви можно сохранить в переменной. Как и в случае с секциями case в блоках switch .
$name = match(2) 1 => 'One', 2 => 'Two', >; echo $name; // => Two
Множественные условия
Для выражения match можно задать несколько условий, указав их через запятую. Тогда выражение будет похоже на каскад секций case в блоке switch .
match($case) 'one' => 'fizz', 'two', 'three' => 'bazz', >;
Для условий $case === ‘two’ и $case === ‘three’ будет возвращено значение ’bazz’ .
Однострочные выражения
В отличие от блоков switch , которые содержат произвольное количество выражений, в каждой ветви match есть только одно выражение. Поэтому так делать нельзя:
match($name) 'foo' => initFoo(); processFoo(); >;
Отсутствие оператора break
Выражение match выполняет только первую ветвь алгоритма, который соответствует условию. В отличие от оператора switch , в match сквозное исполнение не происходит.
А чтобы при использовании switch не забыть о ключевом слове break , PHP продолжает исполнять команды следующей секции case :
switch ('test') case 'test': sendTestAlert(); case 'send': sendNuclearAlert(); >
Здесь мы пропустили оператор break . В результате сквозного исполнения кода выполняется функция sendNuclearAlert() , хотя этого не должно было произойти.
Для выражения match не требуется ключевое слово break . Оно выполняет одну ветвь, возвращает значение и останавливается:
match ('test') 'test' => sendTestAlert(), 'send' => sendNuclearAlert(), >;
Читайте также: «Комьюнити у PHP сейчас одно из самых активных»: интервью c разработчиком Yii Framework Александром Макаровым
Шаблон default
Для выражения match можно задать шаблон default , аналогично похожей конструкции в блоке switch .
Ветвь default совпадает со всеми условиями, которым не нашлось других совпадений.
match ('Qux') 'foo' => . , 'bar' => . , default => echo 'Unknown: ' . $name, >; // => Unknown: Qux
Отсутствие совпадений
Если блок switch не обнаруживает совпадения, то PHP продолжает выполнять код. Выражение match носит исчерпывающий характер. Если совпадения не найдены, и нет конструкции default , выражение выдает исключение \UnhandledMatchError .
$value = 3; match($value) 1 => 'One', 2 => 'Two', >;
Если ввести такое выражение match , получим ошибку:
Fatal error: Uncaught UnhandledMatchError in .
Исключение UnhandledMatchError
Если проверяемое выражение не совпало ни с одним из условий, выбрасывается исключение \UnhandledMatchError .
Это подвид \Error , новый класс исключений в PHP 8. Почитать о структуре базовых исключений PHP, включая новые классы, можно в этой статье.
Добавить эту функциональность в предыдущие версии PHP можно с помощью полифилла:
class UnhandledMatchError extends \Error <>
Строгое сравнение без приведения типов
Одна из особенностей выражения match заключается в том, что оно не только сравнивает значение, но и учитывает тип выражения.
function read(mixed $key): string return match ($key) 1 => 'Integer 1', '1' => 'String 1', true => 'Bool true', [] => 'Empty array', [1] => 'Array [1]', >; > read(1); // "Integer 1" read('1'); // "String 1" read(true); // "Bool true"
Блок switch использует слабое сравнение (==) и приводит типы к нужному значению. В выражениях match все ветви кода, соответствующие условию, подлежат строгому сравнению (===) . Это защищает разработчиков от ошибок.
В примере выше каждая ветвь проверяется на предмет соответствия значения и типа.
Сравнение с произвольными выражениями
match позволяет сравнить значение с выражением.
match($foo) 404 => 'Page not found', Response::REDIRECT => 'Redirect', $client->getCode() => 'Client Error', $response->getCode() => 'Response Error', default => 'Unknown error' >;
Здесь match ищет совпадение для $foo в следующем порядке:
- $foo === 404
- $foo === Response::REDIRECT
- $foo === $client->getCode()
- $foo === $response->getCode()
- default
Проверка кода завершится, как только будет обнаружено совпадение.
Чем различаются match и switch
С какими версиями PHP совместим match
Код с выражением match работает только в PHP версии 8.0 и новее. Для более ранних версий можно бэкпортировать класс исключений \UnhandledMatchError .
Если выполнить код с выражением match в предыдущих версиях PHP, возникнет ошибка анализа:
Parse error: syntax error, unexpected '=>' (T_DOUBLE_ARROW) in . on line .
Что выбрать: match или switch
Итак, выражение match — это более строгая и современная альтернатива для оператора switch .
В некоторых случаях switch более универсален, особенно если нужно использовать многострочные блоки кода. Но у этого оператора много недостатков, которые исправлены в match . В целом match выигрывает благодаря точности и более широким возможностям сопоставления с переданным значением.
Станьте профессиональным PHP-разработчиком с нуля за 10 месяцев На Хекслете есть профессия «PHP-разработчик». Пройдите ее, чтобы изучить один из самых известных языков программирования, освоить популярные фреймворки и создать большое портфолио с проектами на GitHub.