Оператор Элвис (?:) и оператор объединения с null (??) в PHP: в чем разница?
Главное отличие: проверка на "истинность" vs проверка на существование и null
Вы столкнулись с классической путаницей. Давайте раз и навсегда разберемся. Ключевое отличие в том, что именно проверяет каждый оператор.
- Оператор Элвис
?:проверяет, является ли левое выражение "истинным" (truthy) в логическом контексте. Если да — возвращает его, если нет — возвращает правое значение. - Оператор объединения с null
??проверяет, существует ли переменная и не равна ли онаnull. Если да — возвращает левое значение, если переменная не определена или равнаnull— возвращает правое.
Разбор ваших примеров
Пример 1: Пустая строка
$username = $_POST['username'] ?: 'Гость'; // Пустая строка -> 'Гость'
$username = $_POST['username'] ?? 'Гость'; // Пустая строка -> '' (пустая строка)
Пустая строка "" в PHP считается ложным (falsy) значением. Поэтому оператор Элвис видит: "Ага, слева ложь, значит, беру правое значение — 'Гость'". Оператор ?? же проверяет только на null и существование. Пустая строка — это не null, она существует. Поэтому он возвращает её как есть.
Пример 2: Число 0 и false
$timeout = $config['timeout'] ?: 30; // 0 -> 30
$debug = $config['debug'] ?? true; // false -> false
Число 0 — это falsy значение. Элвис заменяет его на 30. А false — это хоть и falsy, но не null. Оператор ?? видит, что значение существует и не равно null, и возвращает его (false).
Полный список "falsy" значений (для Элвиса)
Оператор ?: считает ложными и заменяет следующие значения:
nullfalse0и0.0""(пустая строка) и"0"[](пустой массив)
Когда что использовать?
- Используйте
??когда:- Вы хотите проверить, определена ли переменная (ключ массива) и не равна ли она
null. - Вам нужно безопасно получить значение, которое может отсутствовать (например, из
$_GET,$_POST, результата запроса к БД). - Нормальные значения включают
0,false, пустую строку.
- Вы хотите проверить, определена ли переменная (ключ массива) и не равна ли она
- Используйте
?:когда:- Вы хотите предоставить запасное значение для любого "пустого" или "ложного" результата.
- Например, при выводе счётчика:
echo $count ?: 'Нет записей';(если 0 — покажем сообщение). - Вы уверены, что
0,falseили пустая строка не являются допустимыми результатами.
Продвинутый совет: цепочка операторов
Их можно комбинировать. Например, получить значение из запроса, а если его нет — из кэша, а если и там пусто — значение по умолчанию:
$value = $_GET['id']
?? $cache->get('last_id')
?: 1;
// Сначала проверим $_GET, потом кэш (если null), потом применим Элвиса к результату из кэша
Но будьте осторожны: ?? имеет более высокий приоритет, чем ?:, поэтому скобки тут расставлены правильно слева направо.
Запомните простое правило: Элвис проверяет "есть ли что-то"? (truthy), а null-коалесцент проверяет "существует ли что-то"? (not null).
<<Дополнение: синтаксический сахар и вложенность
Коллега выше всё верно объяснил. Хочу добавить пару важных моментов, которые часто упускают новички.
1. Оператор ?? можно "цепочкой"
Это его уникальная фишка. Вы можете проверить несколько переменных подряд, и оператор вернёт первую существующую не-null:
$name = $firstName ?? $nickname ?? 'Безымянный';
С Элвисом так не получится — он будет проверять на truthy каждое значение, что может дать неожиданный результат, если одно из них равно 0 или false.
2. Проблема с isset()
Оператор ?? внутри себя использует isset(). Это значит, что он не вызовет ошибку (Notice), если переменная или ключ массива не существует. Элвис же ?: сначала попытается прочитать значение, и если его нет — вы получите Warning: Undefined array key. Поэтому для работы с внешними данными ($_GET, $_POST) ?? гораздо безопаснее.
3. Когда Элвис всё же лучше
Представьте, что вы пишете функцию для форматирования числа:
function formatCount($count) {
return $count ?: '0 (нет данных)';
}
Здесь 0 — это действительно "нет данных", и Элвис отработает идеально. Если бы вы использовали ??, то при передаче 0 функция вернула бы "0", что вам не нужно.
Итог: ?? — для безопасного доступа к данным, ?: — для логических подстановок "по умолчанию".