Это ошибка в нуль-операторе объединения PHP или ожидаемое поведение? - PullRequest
0 голосов
/ 20 марта 2019

Я споткнулся об операторе if, использующем оператор PHP null coalesce, не ведущий себя как «ожидаемый». Рассматриваемый код выглядит примерно так:

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'] выдаче уведомления.

Мой вопрос: это ожидаемое поведение оператора слияния в PHP? Я ожидал, что он будет сильнее, чем, например, оператор || (или).
С другой стороны, в RFC (https://wiki.php.net/rfc/isset_ternary), есть явный пример:

var_dump(0 || 2 ?? 3 ? 4 : 5); // ((0 || 2) ?? 3) ? 4 : 5 => int(4)

, что может указывать, приведенный выше пример - правильное поведение.

Что ты думаешь? Должно ли это быть сообщено как ошибка? Я знаю, что это не «правильный» вопрос, однако, так как я не смог найти сообщение об ошибке / обсуждение / ветку об этом, я подумал, что должен быть ресурс, документирующий это.
Если вы / моды не согласны, я снова сниму вопрос.

1 Ответ

4 голосов
/ 20 марта 2019

Это ожидаемое поведение из-за приоритета оператора

|| имеет более высокий приоритет, чем ??, поэтому ваше первоначальное утверждение рассматривается как

if ($foo['bar'] ?? (false || $foo['baz']) ?? false)
...