(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. Я не защищаю этот тип отладки, но я видел это довольно много раз.