Выражение match
switch выбирает, какие строки выполнить. Но чаще от выбора нужно значение: название дня, цена, надпись на кнопке. Со switch его приходится присваивать в каждой ветке и не забывать break. Для такого выбора в PHP 8 появилось выражение match.
Вернёмся к коридору с дверями. Вахтёр у match строже: номер на билете он сверяет буква в букву, и цифра 7, написанная от руки, для него не то же, что напечатанное число. В коридор он вас не пускает, а сразу выдаёт талон с ответом — значение.
<?php
$day = 7;
$kind = match ($day) {
6, 7 => 'weekend',
default => 'workday',
};
echo $kind, "\n"; // weekendРазберём по частям:
match ($day)— значение, которое будут сравнивать;6, 7 => 'weekend'— ветка: слева через запятую значения, справа результат;default => 'workday'— ветка для всех остальных значений;- точка с запятой после
}нужна, потому что весьmatchстоит внутри присваивания.
$day равен 7 и совпадает со значением первой ветки, поэтому match даёт 'weekend'. Это значение попадает в $kind, и echo его печатает.
Выражение и инструкция
Выражение — код, у которого есть значение: 2 + 3, $age >= 18, тернарный оператор. Как вы уже знаете, инструкция — команда программы: она выполняет действие, но значения не даёт (echo, if, switch). match относится к выражениям, поэтому его можно присвоить, передать в echo или вернуть из функции через return.
Из этого вытекают остальные отличия от switch:
- в ветке
matchстоит одно выражение, а не набор строк; - ветки не проваливаются: выполняется ровно одна, и
breakне нужен; - несколько значений с одним результатом пишут через запятую, а не метками подряд.
Строгое сравнение
match сравнивает значение с ветками через ===: совпасть должны и тип, и значение.
$input = '7';
$label = match ($input) {
7 => 'number',
'7' => 'string',
default => 'unknown',
};
echo $label, "\n"; // stringРазберём по шагам:
- В
$inputлежит строка'7'. - Ветку
7matchпропускает: строка'7'не тождественна числу7. - Ветка
'7'совпадает — это та же строка того же типа, иmatchдаёт'string'.
switch на месте match выбрал бы первую ветку, потому что '7' == 7 истинно.
Когда ни одна ветка не подошла
switch без подходящей метки молча ничего не делает. match так не может, ведь выражение обязано дать значение. Если ни одна ветка не подошла и default нет, match бросает ошибку UnhandledMatchError, и программа останавливается. Например, для $day = 9 и единственной ветки 6, 7 => 'weekend' PHP пишет:
Fatal error: Uncaught UnhandledMatchError: Unhandled match case 9Здесь аналогия с вахтёром заканчивается. Настоящий вахтёр без подходящей двери развёл бы руками и отпустил вас, а match поднимает тревогу и останавливает всю программу. Это полезно: забытый случай виден сразу, а не через месяц по пустой строке в отчёте.
match (true) для диапазонов
Ветки могут проверять не только конкретные значения. В match (true) слева в ветках стоят условия, и match ищет первое, которое даёт ровно true:
$score = 85;
$grade = match (true) {
$score >= 90 => 'A',
$score >= 75 => 'B',
$score >= 50 => 'C',
default => 'F',
};
echo $grade, "\n"; // BУсловия проверяются сверху вниз, как в цепочке elseif: 85 >= 90 ложно, 85 >= 75 истинно, поэтому $grade получает 'B'. Сравнение здесь тоже строгое. Условие-строка 'Anna' истинно, но с true не совпадёт: нужен именно true, какой даёт сравнение.
switch или match
Этот вопрос часто задают на собеседовании: «Чем match отличается от switch?» Ответ:
match— выражение и даёт значение, аswitch— инструкция;matchсравнивает через===, аswitch— через==;- у
matchнет проваливания, иbreakне нужен; matchбез подходящей ветки бросаетUnhandledMatchError, аswitchмолча ничего не делает.
switch остаётся уместен, когда в ветке нужно выполнить несколько инструкций: ветка match — одно выражение.
Частая ошибка
Номер страницы взяли из адреса, и он пришёл строкой '2', а значения в ветках match написаны числами:
$page = '2';
$title = match ($page) { // ✗
1 => 'home',
2 => 'about',
};
echo $title, "\n";Fatal error: Uncaught UnhandledMatchError: Unhandled match case '2'Строка '2' не тождественна числу 2, ветки default нет, и match бросает ошибку. Приведите значение к нужному типу перед сравнением: match ((int) $page).
Главное
match— выражение: он даёт значение одной подходящей ветки, без проваливания и безbreak.- Ветки сравниваются через
===, поэтому строка'2'не совпадает с числом2. - Без подходящей ветки и без
defaultmatchбросаетUnhandledMatchError. match (true)выбирает первую ветку, чьё условие даётtrue.