PHP 8: Новое выражение Match. Как им пользоваться?

PHP 8: Новое выражение Match. Как им пользоваться?

PHP 8 представил нам новое выражение — match — очень сильный функционал, который зачастую будет отличной альтернативой оператору switch. Я говорю здесь «зачастую», потому что как match, так и switch имеют свою область применения, часто не пересекающихся друг с другом. Итак, давайте рассмотрим различия между ними. Для начала сравним их.

PHP 8 представил нам новое выражение — match — очень сильный функционал, который зачастую будет отличной альтернативой оператору switch. Я говорю здесь «зачастую», потому что как match, так и switch имеют свою область применения, часто не пересекающихся друг с другом. Итак, давайте рассмотрим различия между ними. Для начала сравним их. Вот один из примеров применения оператора switch в сфере разработки crm:

switch($clientStatus) {

case 'Open':

case 'Not assigned':

$discount = null;

break;

case 'First buyer':

$discount = 10;

break;

case 'Second buyer':

$dicount = 20;

break;

case 'VIP':

$discount = 30;

break;

default:

$discount = 5;

break;

}

 

А вот как будет выглядеть назначение скидки по статусу клиента в match:

 

$discount = match($clientStatus) {

'Open', 'Not assigned' => null,

'First buyer' => 10,

'Second buyer' => 20,

'VIP' => 30,

default => 5

}

 

Как вы могли увидеть из этих двух примеров, match значительно короче в написании, потому что:

  • Ему не требуется ключевое слово break;
  • Он может объединять несколько условий в одно через запятую;
  • Он возвращает значение, поэтому вы можете сохранить его в переменной.

Поэтому, с синтаксической точки зрения, match значительно проще в написании. Однако, если мы копнём глубже, то можем увидеть куда больше отличий.

Match - это выражение

Match принято называть выражением (expression), тогда как switch - оператором (statement). Между этими двумя понятиями в теории лежит большая разница. Выражение совмещает в себе значение и вызов функции и его можно назначить переменной. Другими словами, оно возвращает какое-то значение. Поэтому мы можем хранить результат вызова match в какой-то переменной. В случае со switch это не возможно.

Отсутствие приведения типов

При сравнении значений match сравнивает и типы значений. Иными словами, при сравнении используется оператор ===, тогда как в switch используется ==.

Поэтому, у вас могут случится ситуации, когда вы захотите, чтобы PHP автоматически приводил типы к нужному значению. Именно это в первую очередь и объясняет, почему вы не можете заменить match вместо switch во всём коде.

$clientType = "2";

$redirectUrl = match($clientType) {

2 => '/discount',

3 => '/buy',

default => '/',

};

 

// $redirectUrl = '/'

 

Неизвестные значения выбрасывают ошибку

Если вы не укажете ключевое слово default и когда match не может найти никаких совпадений в перечислении, PHP выбросит исключение UnhandledMatchError в процессе исполнения. И снова мы видим больше ограничений, но всё это защищает разработчиков от возможных появлений багов.

$clientType = 5;

$redirectUrl = match($clientType) {

2 => '/discount',

3 => '/buy',

};

// UnhandledMatchError

Выражение должно умещаться в одной строке

Вы можете написать только одно выражение. Т.е. такое выражение у вас вызовет ошибку:

$a = 5;

$discount = match($clientStatus) {

'Open', 'Not assigned' => if ($a > 5) {

4

} else {

6

},

'First buyer' => 10,

}

 

В этом случае вам потребуется как минимум использовать тернатный оператор.

Совмещение условий

Я ранее отмечал, что у match отсутствует ключевое слово break; это также означает, что match не разрешает совмещать условия. Но с другой стороны вы можете писать несколько условий в одну строчку, разделяя их запятыми:

$discount = match($clientStatus) {

'First buyer', 'Second buyer', 'VIP' => 10,

}

Сложные условия и производительность

Когда обсуждалось внедрение match в сообществе, некоторые разработчики говорили, что нет никакой необходимости его внедрения, т.к. то же самое можно сделать используя обычные массивы. Посмотрите на пример ниже, когда мы хотим найти значения, где ключи - это поиск по regex. Здесь мы используем нотацию массива:

 

$message = [

$this->matchRegex($line) => 'match A',

$this->matchesOtherRegex($line) => 'match B'

][$search] ?? 'no match';

 

Но здесь есть загвоздка - подобный подход запустит все функции regex во время построения массива. Match, с другой стороны будет запускать всё построчно, а это более производительно.

Выбрасывание исключений

Так как мы говорим о PHP 8, то исключение можно выбросить непосредственно в самом match:

$discount = match($clientStatus) {

'Open', 'Not assigned' => throw new DomainException('This type of client not allowed here!'),

'First buyer' => 10,

'Second buyer' => 20,

'VIP' => 30,

default => 5

}

 

Итак, что использовать - switch или match?

Если сделать краткий итог, то можно сказать, что match - это более строгая и более современная версия его младшего брата switch.

Есть случаи, когда match предлагает большую гибкость, особенно когда мы говорим о более сложных условиях в несколько строк и жонглирование типами. С другой стороны, проверка по regex, которую я приводил выше, ограничения, которые гарантируют меньше ошибок, существенно сделают жизнь разработчиков проще.

Често признаться, раньше я редко использовать switch, ввиду его сложного синтаксиса. И эти проблемы решил match. Конечно, он ещё не совершеннен, поэтому есть случаи, когда вы будете использовать switch, а когда match.