Перейти к содержимому
Теория · Условия · урок 7 из 8

Выражение match

switch выбирает, какие строки выполнить. Но чаще от выбора нужно значение: название дня, цена, надпись на кнопке. Со switch его приходится присваивать в каждой ветке и не забывать break. Для такого выбора в PHP 8 появилось выражение match.

Вернёмся к коридору с дверями. Вахтёр у match строже: номер на билете он сверяет буква в букву, и цифра 7, написанная от руки, для него не то же, что напечатанное число. В коридор он вас не пускает, а сразу выдаёт талон с ответом — значение.

PHP
<?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 сравнивает значение с ветками через ===: совпасть должны и тип, и значение.

PHP
$input = '7';
$label = match ($input) {
    7 => 'number',
    '7' => 'string',
    default => 'unknown',
};
echo $label, "\n"; // string

Разберём по шагам:

  1. В $input лежит строка '7'.
  2. Ветку 7 match пропускает: строка '7' не тождественна числу 7.
  3. Ветка '7' совпадает — это та же строка того же типа, и match даёт 'string'.

switch на месте match выбрал бы первую ветку, потому что '7' == 7 истинно.

Когда ни одна ветка не подошла

switch без подходящей метки молча ничего не делает. match так не может, ведь выражение обязано дать значение. Если ни одна ветка не подошла и default нет, match бросает ошибку UnhandledMatchError, и программа останавливается. Например, для $day = 9 и единственной ветки 6, 7 => 'weekend' PHP пишет:

TEXT
Fatal error: Uncaught UnhandledMatchError: Unhandled match case 9

Здесь аналогия с вахтёром заканчивается. Настоящий вахтёр без подходящей двери развёл бы руками и отпустил вас, а match поднимает тревогу и останавливает всю программу. Это полезно: забытый случай виден сразу, а не через месяц по пустой строке в отчёте.

match (true) для диапазонов

Ветки могут проверять не только конкретные значения. В match (true) слева в ветках стоят условия, и match ищет первое, которое даёт ровно true:

PHP
$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 написаны числами:

PHP
$page = '2';
$title = match ($page) { // ✗
    1 => 'home',
    2 => 'about',
};
echo $title, "\n";
TEXT
Fatal error: Uncaught UnhandledMatchError: Unhandled match case '2'

Строка '2' не тождественна числу 2, ветки default нет, и match бросает ошибку. Приведите значение к нужному типу перед сравнением: match ((int) $page).

Главное

  • match — выражение: он даёт значение одной подходящей ветки, без проваливания и без break.
  • Ветки сравниваются через ===, поэтому строка '2' не совпадает с числом 2.
  • Без подходящей ветки и без default match бросает UnhandledMatchError.
  • match (true) выбирает первую ветку, чьё условие даёт true.