Перейти к содержимому
Теория · Операторы и сравнение · урок 7 из 8

Операторы для null: ?? и ?:

Значение в программе есть не всегда. Переменную могли не задать, или в ней лежит null — «значения нет». Тогда нужна замена по умолчанию: «гость» вместо имени, пять вместо лимита.

Вернёмся к двум кассирам. Покупатель протягивает купон на скидку. Снисходительный кассир считает пустым любой купон, на котором ничего толком не написано: ноль, пустую строку. Строгий берёт скидку по умолчанию, только если купона нет совсем.

В PHP строгого кассира здесь зовут ??, а снисходительного — ?:.

PHP
<?php

$discount = null;
echo $discount ?? 5, "\n"; // 5
echo $coupon ?? 'none', "\n"; // none
$discount = 0;
echo $discount ?? 5, "\n"; // 0
echo $discount ?: 5, "\n"; // 5

Давайте разберём программу по строкам:

  1. $discount ?? 5 печатает 5: в $discount лежит null.
  2. $coupon ?? 'none' печатает none: переменной $coupon нет совсем, и PHP не выдаёт предупреждения.
  3. После $discount = 0 выражение $discount ?? 5 печатает 0: ноль — настоящее значение, а не null.
  4. $discount ?: 5 печатает 5: для ?: ноль считается пустым.

Оператор ??

Оператор объединения с null записывают как $a ?? $b:

  • если $a задана и не равна null, результат — $a;
  • иначе результат — $b.

?? сначала проверяет, есть ли переменная, и только потом читает её. Поэтому на незаданной переменной он молчит, хотя обычное чтение $coupon дало бы Warning: Undefined variable $coupon.

Цепочка ??

Операторы ?? можно ставить друг за другом: $a ?? $b ?? 'x'. PHP проверяет слева направо и берёт первое значение, которое задано и не равно null. Если $a и $b равны null, результат — 'x'.

Оператор ??=

$limit ??= 20 записывает 20 в $limit, только если переменная не задана или равна null:

PHP
$limit = null;
$limit ??= 20;
$page = 0;
$page ??= 1;
echo $limit, ' ', $page, "\n"; // 20 0

В $limit теперь 20, а $page остаётся 0: ноль задан и не равен null.

Оператор ?:

$a ?: $b берёт $b, когда $a превращается в false. Из значений, которые вы уже знаете, в false превращаются:

  • false и null;
  • 0 и 0.0;
  • пустая строка '' и строка '0'.

Это те же значения, которые (bool) превращает в false. Для ?: пустая строка в $name значит «имени нет», поэтому $name ?: 'guest' даёт guest.

В отличие от ??, оператор ?: читает переменную как обычно. Если её не задали, PHP выдаст предупреждение, как при любом чтении незаданной переменной.

Чем ?? отличается от ?:, часто спрашивают на собеседовании. Ответ:

  • ?? заменяет только null и незаданную переменную, причём без предупреждения;
  • ?: заменяет всё, что превращается в false, включая 0 и '';
  • ?: читает переменную как обычно, и незаданная переменная даёт Warning.

Здесь картинка с кассирами упрощает. Живой кассир спросит, что вы имели в виду, а ?: не спрашивает: для него ноль всегда пустота, даже если это честная цена в ноль рублей. Когда 0 или '' — допустимые значения, берите ??.

Частая ошибка

Имя по умолчанию подставляют через ?:, а переменную никто не задал:

PHP
echo $nickname ?: 'guest', "\n"; // ✗
TEXT
Warning: Undefined variable $nickname

PHP печатает предупреждение, а затем guest: ?: читает $nickname как обычную переменную, а её нет. Программа продолжает работу, но предупреждение говорит об ошибке в коде. Замените ?: на ??: $nickname ?? 'guest' печатает guest без предупреждения.

Главное

  • ?? подставляет правую часть, когда левой нет или в ней null, и не выдаёт предупреждения.
  • ?: подставляет правую часть для всего, что превращается в false: 0, '', '0', null.
  • $x ??= 20 записывает 20, только если $x не задана или равна null.
  • Когда ноль или пустая строка — допустимые значения, выбирайте ??.