(PHP имеет ||
а также OR
, JS имеет только ||
.)
JS. В соответствии с MDN ||
имеет более высокий приоритет, чем =
, Так что это не работает:
a || a = 1;
потому что это оценивается как:
(a || a) = 1;
что приводит к «Неверной левой стороне в назначении». Я это понимаю. В этом есть смысл.
PHP. В соответствии с PHP.net он работает так же для PHP: ||
до =
, Тем не менее, я использую это все время:
$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()
, который не имеет смысла и должен потерпеть неудачу, но PHP оценивает его как !($a = foo())
потому что он любит исключения.
Дополнительный вопрос: Как вы думаете if ( $d = $c && $e = $b && $f = $a )
делает? https://3v4l.org/3P2hN Я не понимаю … Я понимаю, второй и третий случай (с and
), только не то, что происходит в первом.
В соответствии с zend_language_parser.y код анализируется эквивалентно $a || ($a = 1)
а также $a or ($a = 1)
в каждом случае соответственно.
Как резюмирует Мельпомена, задание производств не инфиксные бинарные операторы над выражениями; скорее операторы присваивания ограничены производства где левая сторона должен быть 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
Таким образом, круглые скобки следует, как правило, использовать при смешивании операторов присваивания с операторами более высокого приоритета, особенно когда результат такого может быть … неясным.
Каким бы противоречивым это ни казалось на первый взгляд, это четко определенная грамматика, но технические детали скрыты за некоторой довольно непрофессиональной документацией; и правила немного отличаются от правил в других C-синтаксисоподобных языках. Отсутствие официального EBNF в документации не помогает.
Несмотря на детали разбора, $a || $a = ..
код (который является действительный и четко определенный синтаксис) должен оставаться четко определенным с точки зрения оценки, поскольку левая часть «или» должна встречаться до правой из-за гарантированное короткое замыкание.
Для сравнения, в JavaScript a || a = 1
анализируется как (a || a) = 1
— который также является синтаксически «действительным» кодом — согласно Правила грамматики ECMAScript. Тем не мение, a || a
не дает действительный тип справочной спецификации и, следовательно, время выполнения ReferenceError выбрасывается.
Что касается вашего дополнительного вопроса: 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;
эквивалентно этому:
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, чтобы включить / отключить отладку. Я не защищаю этот тип отладки, но я видел это довольно много раз.