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;

会导致"赋值时左侧无效"。我理解。有道理。

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。在每种情况下,代码分别被解析为$a || ($a = 1)$a or ($a = 1)

正如melpomene所总结的,赋值结果是而不是中缀二进制操作符在表达式上;rather 赋值操作符是受限生成,其中左侧必须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是否相同,它使$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来打开/关闭调试。我并不提倡这种调试方式,但是我已经见过很多次了