Ответ 1
В соответствии с zend_language_parser.y код анализируется эквивалентно $a || ($a = 1)
и $a or ($a = 1)
в каждом случае соответственно.
Как суммировано melpomene, постановка присваивания не является инфиксными двоичными операторами над выражениями; скорее операторы присваивания ограничены производством, где левая часть должна быть variable
.
Таким образом, PHP анализирует выражение единственным возможным способом.
Документация правильна о приоритете.. где она применяется.
Таким образом, $a || $a = 1
следует (обратным) произведениям:
variable "||" variable "=" expr
variable "||" expr_without_variable
expr "||" expr
expr
Случай !$a = foo()
аналогичен и анализируется как !($a = foo())
после выполнения (обратных) производств:
"!" variable "=" expr
"!" expr_without_variable
"!" expr
expr
Теперь, как насчет $d = $c && $e = $b && $f = $a
? Он не анализируется как ($d = $c) && ..
, хотя &&
имеет более высокий приоритет, чем назначение. Он фактически анализируется как $d = ($c && ($e = ..))
и т.д., Который должен быть завершен проницательным читателем.
В то время как это может быть не случайно замечено, это различие способно производить разные результаты:
$a = (($c = 1) && ($d = 0));
var_dump($a, $c, $d); // => false, 1, 0
$b = ($e = 1 && $f = 0); // => $b = ($e = (1 && ($f = 0)));
var_dump($b, $e, $f); // => false, false, 0
Таким образом, скобки следует, как правило, использовать при смешивании операторов присваивания с операторами с более высоким приоритетом, особенно когда результат такой может быть неясным.
Как неясно, как это может показаться на первый взгляд, это четко определенная грамматика, но технические детали зарыты за какой-то довольно непрофессиональной документацией; и правила отличаются тонко от правил на других языках, подобных синтаксису. Отсутствие официального документа EBNF в документации не помогает.
Несмотря на детали синтаксического анализа, код $a || $a = ..
(который является допустимым и четко определенным синтаксисом) должен оставаться корректным с точки зрения оценки, так как левая сторона "или" должна произойти до права из-за гарантированное короткое замыкание.
Для сравнения, в JavaScript, a || a = 1
анализируется как (a || a) = 1
- также синтаксически "действительный" код - за Правила грамматики ECMAScript. Тем не менее, a || a
не дает допустимого ссылочного типа спецификаций и, таким образом, запускается ReferenceError времени выполнения.