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

前端 未结 3 727
猫巷女王i
猫巷女王i 2020-12-14 19:09

(PHP has || and OR. JS only has ||.)

JS. According to MDN || has higher precedence than =<

3条回答
  •  醉梦人生
    2020-12-14 20:01

    According to zend_language_parser.y the code is parsed equivalently to $a || ($a = 1) and $a or ($a = 1) in each case, respectively.

    As summarized by melpomene, the assignment productions are not infix binary operators over expressions; rather assignment operators are restricted productions where the left-hand side must be a variable production.

    Per a borrowed quote:

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

    The documentation is correct about the precedence .. where it applies.


    Thus $a || $a = 1 follows the (reversed) productions of:

    variable "||" variable "=" expr
    variable "||" expr_without_variable
    expr "||" expr
    expr
    

    The case of !$a = foo() is similar and is parsed as !($a = foo()) after following the (reversed) productions:

    "!" variable "=" expr
    "!" expr_without_variable
    "!" expr                 
    expr
    

    Now, how about $d = $c && $e = $b && $f = $a? It is not parsed as ($d = $c) && .. even though the && does have a higher precedence than the assignment. It is actually parsed as $d = ($c && ($e = ..)) and so on, to be completed by the astute reader.

    While it might not be casually noticed, this difference is capable of producing varying results:

    $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
    

    Parenthesis should thus generally be used when mixing assignment operators with operators of higher precedence, especially when the result of such may be .. unclear.

    As inconsistent as this may initially seem, it is a well-defined grammar - but the technical details are buried behind some fairly layman documentation; and the rules differ subtly from those in other C-syntax-like languages. The lack of an official EBNF in the documentation doesn't help.


    Despite the parsing details, the $a || $a = .. code (which is valid and well-defined syntax) should remain well-defined from an evaluation viewpoint as the left side of the 'or' must occur prior to the right due to guaranteed short-circuiting.


    For contrast, in JavaScript, a || a = 1 is parsed as (a || a) = 1 - which is also syntactically 'valid' code - per the ECMAScript Grammar Rules. However, a || a does not yield a valid Reference Specification Type and thus a runtime ReferenceError is thrown.

提交回复
热议问题