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Подсказка: справа от стрелки => может стоять любое выражение, в том числе тернарный оператор.
Полезное
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Подсказка: справа от стрелки => может стоять любое выражение, в том числе тернарный оператор.
Полезное
Ваше упражнение проверяется по этим тестам
<?php
namespace HexletBasics\Conditionals\MatchExpression;
use HexletBasics\Exercise\TestCase;
class SolutionTest extends TestCase
{
public function test()
{
$this->assertEquals(600, calculateDeliveryCost('canada', 0.5));
$this->assertEquals(600, calculateDeliveryCost('canada', 1));
$this->assertEquals(900, calculateDeliveryCost('canada', 2));
$this->assertEquals(800, calculateDeliveryCost('usa', 1));
$this->assertEquals(1200, calculateDeliveryCost('usa', 3));
$this->assertEquals(700, calculateDeliveryCost('germany', 0.3));
$this->assertEquals(1000, calculateDeliveryCost('germany', 1.5));
$this->assertNull(calculateDeliveryCost('france', 1));
}
}Решение учителя откроется через:
20:00
