(PHP имеет ||
и OR
. JS имеет только ||
.)
JS. Согласно MDN ||
имеет более высокий приоритет, чем =
. Так что это не работает:
a || a = 1;
потому что он оценивается как:
(a || a) = 1;
что приводит к «Недопустимая левая сторона при назначении». Я это понимаю. В этом есть смысл.
PHP. Согласно PHP.net, он работает так же для PHP: ||
before =
. Тем не менее, я использую это все время:
$a || $a = 1;
Почему это работает в PHP? И в довершение всего: PHP OR
имеет более низкий приоритет, чем =
, поэтому они не должны делать то же самое:
$a || $a = 1; $a OR $a = 1;
но они … https://3v4l.org/UWXMd
Я думаю, что JS ' ||
работает в соответствии с таблицей MDN, а PHP OR
работает как таблица PHP, но PHP ||
не должно работать так, как есть.
Это еще одна странная причуда PHP?
В руководстве также упоминается следующее:
Хотя
=
имеет более низкий приоритет, чем большинство других операторов, PHP все равно позволит выражениям, аналогичным следующим:if (!$a = foo())
, и в этом случае возвращаемое значениеfoo()
помещается в$a
.
В таблице приоритетов указано, что PHP должен оценивать (!$a) = foo()
A (!$a) = foo()
, что не имеет смысла и должно потерпеть неудачу, но PHP оценивает его как !($a = foo())
, потому что он любит исключения.
Последующий вопрос: что вы думаете, if ( $d = $c && $e = $b && $f = $a )
? https://3v4l.org/3P2hN Я не понимаю … Я понимаю второй и третий случай (с and
), просто не то, что происходит в первом.
Согласно zend_language_parser.y код анализируется эквивалентно $a || ($a = 1)
$a || ($a = 1)
и $a or ($a = 1)
в каждом случае соответственно.
Как суммировано melpomene, производственные задания не являются инфиксными двоичными операторами над выражениями; скорее, операторы присваивания ограничены производством, где левая сторона должна быть variable
производством.
По заимствованной цитате :
Таким образом, PHP анализирует выражение единственным возможным способом.
Документация правильна в отношении приоритета .. там, где она применяется.
Таким образом, $a || $a = 1
$a || $a = 1
следует (обратным) произведениям:
variable "||" variable "=" expr variable "||" expr_without_variable expr "||" expr expr
Случай !$a = foo()
A !$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 = ..
Код $a || $a = ..
(который является допустимым и четко определенным синтаксисом) должен оставаться четко определенным с точки зрения оценки, поскольку левая сторона «или» должна произойти до права из-за гарантированного короткого замыкания .
Для контраста, в JavaScript, a || a = 1
a || a = 1
анализируется как (a || a) = 1
– который также является синтаксически «действительным» кодом – согласно правилам грамматики ECMAScript . Однако, a || a
a || a
не дает допустимого ссылочного типа спецификации, и, таким образом, возникает вызов RefereneError.
Что касается вашего последующего вопроса: if ( $d = $c && $e = $b && $f = $a )
– это то же самое, что:
$d = $c; if($d) { $e = $b; if($e) { $f = $a; if($f) { ... } } }
Я предполагаю, что вы это знаете, но некоторые вопросы меня смущают, поэтому я упомянул об этом … = оператор присваивания, а не оператор сравнения. if($a = $b)
не проверяет, являются ли $ a и $ b одинаковыми, он равен $ равному $ b, а затем проверяет, соответствует ли $ a true. if($a == $b)
проверяет, совпадают ли две переменные.
Выражение $a || $a = 1;
$a || $a = 1;
эквивалентно этому:
if ( $a != true ) { $a = 1; }
Очень распространенный вариант этой идеи используется для отладки бедных:
$debug = true; // Thousands of lines of code $debug && printf("Foo: {$foo}"); // More code $debug && printf("Bar: {$bar}");
В этой парадигме для включения / отключения отладки необходимо установить только оператор $debug
для true / false. Я не защищаю этот тип отладки, но я видел это довольно много раз.