JS vs PHP:与逻辑或一起使用时的赋值运算符优先级

JS vs PHP: assignment operator precedence when used with logical-or

(PHP有||OR。JS只有||。)

JS. 根据 MDN || 的优先级高于 =。所以这不起作用:

a || a = 1;

因为它被评估为:

(a || a) = 1;

结果是 "Invalid left-hand side in assignment"。我明白那个。有道理。

PHP. 根据 PHP.net 它对 PHP 的作用相同:||= 之前.但是,我一直使用这个:

$a || $a = 1;

为什么它在 PHP 中有效??最重要的是:PHP 的 OR 的优先级低于 =,因此它们不应该这样做:

$a || $a = 1;
$a OR $a = 1;

但他们确实... https://3v4l.org/UWXMd

我认为 JS 的 || 根据 MDN 的 table 工作,而 PHP 的 OR 的工作方式类似于 PHP 的 table,但是 PHP 的 || 不应该像它那样工作。

这是另一个奇怪的 PHP 怪癖吗?

手册中也提到了这一点:

Although = has a lower precedence than most other operators, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.

优先级 table 指示 PHP 应该计算 (!$a) = foo(),这没有意义并且应该失败,但是 PHP 将其计算为 !($a = foo()),因为它喜欢例外。

后续问题:你认为if ( $d = $c && $e = $b && $f = $a )是做什么的? https://3v4l.org/3P2hN 我不明白...我理解第二种和第三种情况(使用 and),只是不了解第一种情况。

关于您的后续问题:if ( $d = $c && $e = $b && $f = $a ) 等同于:

$d = $c;
if($d) {
    $e = $b;
    if($e) {
        $f = $a;
        if($f) {
            ...
        }
    }
}

我假设你知道这一点,但有些问题让我感到困惑,所以我会提到它...... = 是赋值运算符,而不是比较运算符。 if($a = $b) 不检查 $a 和 $b 是否相同,它使 $a 等于 $b,然后检查 $a 是否为真。 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即可enable/disable调试。 我不是提倡这种类型的调试,但我已经看过很多次了。

根据 zend_language_parser.y,代码在每种情况下分别等效于 $a || ($a = 1)$a or ($a = 1) 解析。

正如 melpomene 总结的那样,赋值产生式 不是 表达式上的中缀二元运算符;相反,赋值运算符是受限产生式,其中左侧必须variable产生式。

根据 borrowed quote:

Thus PHP parses the expression in the only possible way..

关于优先级的文档正确.. 它适用的地方


因此 $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 怎么样?它 not 被解析为 ($d = $c) && .. 即使 && does 的优先级高于赋值。它实际上被解析为 $d = ($c && ($e = ..)) 等等,由精明的人完成 reader.

虽然可能不会随便注意到,但这种差异能够产生不同的结果:

$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 = .. 代码( 有效且定义明确的语法)从评估的角度来看应该保持良好定义,因为左侧由于 guaranteed short-circuiting.

,'or' 的一部分必须出现在右边之前

相比之下,在 JavaScript 中,a || a = 1 被解析为 (a || a) = 1 - 根据 ECMAScript Grammar Rules,这在语法上也是 'valid' 代码。但是,a || a 不会产生有效的参考规范类型,因此会抛出 runtime ReferenceError。