#php #null-coalescing-operator
#php #null-coalescing-operator
Вопрос:
Я наткнулся на оператор if, использующий PHPs null coalesce operator, который ведет себя не так, как «ожидалось». Рассматриваемый код выглядит примерно так:
if ($foo['bar'] ?? false || $foo['baz'] ?? false) { /* ... */ }
меняем его на
if (($foo['bar'] ?? false) || ($foo['baz'] ?? false)) { /* ... */ }
решает это.
Я провел быстрый тест в своем терминале:
root@docker:/application# php -v
PHP 7.2.11-2 ubuntu18.04.1 deb.sury.org 1 (cli) (built: Oct 15 2018 11:40:35) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.11-2 ubuntu18.04.1 deb.sury.org 1, Copyright (c) 1999-2018, by Zend Technologies
with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans
root@docker:/application# php -a
Interactive mode enabled
php > $test = ['foo' => 'bar'];
php > var_dump($test['baz'] ?? null); // as expected
php shell code:1:
NULL
php > var_dump(($test['baz'] ?? null)); // as expected
php shell code:1:
NULL
php > var_dump($test['baz'] ?? null || $test['foobar'] ?? null); // as expected, but there's a Notice
PHP Notice: Undefined index: foobar in php shell code on line 1
PHP Stack trace:
PHP 1. {main}() php shell code:0
php shell code:1:
bool(false)
php > var_dump(($test['baz'] ?? null) || ($test['foobar'] ?? null)); // as expected
php shell code:1:
bool(false)
Теперь, что, я думаю, происходит в тесте № 3, так это то, что он выполняется как
$test['baz'] ?? (null || $test['foobar']) ?? null
итак, если $test['baz']
вычисляется значение unset (что, очевидно, и происходит), выполняется следующий null || $test['foobar']
get, что приводит к $test['foobar']
отправке уведомления.
Мой вопрос: Это ожидаемое поведение оператора null coalesce в PHP? Я вроде ожидал, что он будет привязываться сильнее, чем, например, оператор ||
(or).
С другой стороны, в RFC (https://wiki.php.net/rfc/isset_ternary), есть явный пример:
var_dump(0 || 2 ?? 3 ? 4 : 5); // ((0 || 2) ?? 3) ? 4 : 5 => int(4)
что может указывать на то, что приведенный выше пример является правильным поведением.
Что вы думаете? Должно ли об этом сообщаться как об ошибке? Я знаю, что это не «правильный» вопрос, однако, поскольку я не смог найти отчет об ошибке / обсуждение / ветку об этом, я подумал, что должен быть ресурс, документирующий это.
Если вы / моды не согласны, я снова удалю вопрос.
Комментарии:
1. Если RFC подтверждает поведение, почему это должно быть ошибкой?
2. Разве это не просто приоритет оператора .
||
имеет более высокий приоритет, чем??
.3. @PatrickQ Это точно не подтверждает поведение, но у IMO есть похожий случай. Вот почему я спросил.
4. Я не думаю, что ответ необходим. Это скорее случай RTM.
5. @Barmar ИМО, по этой причине многие вопросы здесь должны исчезнуть. Но опять же, я не согласен со всей новой философией контента ради контента.
Ответ №1:
Это ожидаемое поведение из-за приоритета оператора
||
имеет более высокий приоритет, чем ??
, поэтому ваше исходное утверждение обрабатывается как
if ($foo['bar'] ?? (false || $foo['baz']) ?? false)