PHP: Выражение match

Выражение match появилось в PHP 8 и решает ту же задачу, что и switch: выбирает результат по значению переменной. Конструкции похожи, но match записывается короче и работает как выражение. Сравним их на одном примере. Вот выбор текста по статусу заказа через switch:

<?php

switch ($status) {
    case 'processing':
        $statusText = 'Заказ в обработке';
        break;
    case 'paid':
        $statusText = 'Заказ оплачен';
        break;
    case 'new':
        $statusText = 'Новый заказ';
        break;
    default:
        $statusText = 'Неизвестный статус';
}

То же самое на match занимает меньше места, а результат сразу попадает в переменную:

<?php

$statusText = match ($status) {
    'processing' => 'Заказ в обработке',
    'paid' => 'Заказ оплачен',
    'new' => 'Новый заказ',
    default => 'Неизвестный статус',
};
match (значение) {
  │
  ├── 'a' → результат 1
  ├── 'b' → результат 2
  ├── 'c' → результат 3
  └── default → результат по умолчанию
}

Слева от стрелки => стоит значение для сравнения, справа — любое выражение, которое станет результатом. Ветка default срабатывает, когда не подошло ни одно значение, и играет роль else. Если одному результату соответствует несколько значений, их перечисляют через запятую:

<?php

$type = match ($size) {
    'xs', 's' => 'small',
    'm' => 'medium',
    'l', 'xl' => 'large',
};

Главное отличие от switch в том, что match — это выражение. Вся конструкция вычисляется в значение, поэтому результат сразу присваивают переменной или возвращают из функции. У switch так не получится, для результата нужна отдельная переменная или return внутри case. Есть и другие различия:

  • match сравнивает значения строго, как оператор ===, без автоматического преобразования типов. switch сравнивает нестрого, через ==.
  • В match выполняется ровно одна ветка, поэтому break не нужен. В switch без break управление "проваливается" в следующий case.
  • Если в match ничего не совпало и нет default, программа завершится с ошибкой UnhandledMatchError. switch в этом случае ничего не делает.

Раз match возвращает значение, его результат часто отдают прямо из функции через return:

<?php

function countItems(int $count): ?string
{
    return match ($count) {
        1 => 'one',
        2 => 'two',
        default => null,
    };
}

print_r(countItems(2)); // => two

Технически без match всегда можно обойтись, как и без switch. Но когда нужно выбрать результат по конкретным значениям переменной, match выражает это намерение яснее всего, и читать такой код легче, чем цепочку elseif.

Задание

Реализуйте функцию calculateDeliveryCost(), которая принимает страну доставки и вес посылки в килограммах. Функция должна вернуть стоимость доставки.

Для каждой страны есть два тарифа: для посылок весом до 1 кг включительно и для более тяжелых посылок:

  • 'canada': 600 для посылок до 1 кг, 900 для остальных
  • 'usa': 800 для посылок до 1 кг, 1200 для остальных
  • 'germany': 700 для посылок до 1 кг, 1000 для остальных

Если страна неизвестна, функция должна вернуть null.

Примеры вызова функции:

<?php

calculateDeliveryCost('canada', 0.5); // 600
calculateDeliveryCost('canada', 2);   // 900
calculateDeliveryCost('usa', 1);      // 800
calculateDeliveryCost('france', 1);   // null

Подсказка: справа от стрелки => может стоять любое выражение, в том числе тернарный оператор.

Полезное

Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются