What happens in the expression "$ a +++ (++ $ a)"?

6

I was joking with PHP to see if I could find something that sounded strange with the syntax, inspiring me in the question What happens in 1 ... 1 in PHP? .

I ended up with the code:

$a = 0;

$a+++(++$a)

The above "joke" returned 2 .

Why did 2 return? What detail did PHP process in this sentence?

Test at IDEONE

    
asked by anonymous 05.08.2017 / 21:14

3 answers

9

The expression that PHP perceives will be:

$a++ + (++$a)

Since any expression is parsed from the left, it will occur:

  • The $a++ operation will be analyzed, producing the current value of $a as a result and then incrementing the variable. That is, returns 0 and the value of $a becomes 1;

  • The addition operation + will be analyzed. Since it is an operation that requires two operands, the addition of zero will be done, the value returned in step 1, and the result of ++$a . Then, before the addition, the second operand will be parsed;

  • The ++$a operation will be analyzed. The $a value will be incremented and the result will be returned. As the current value of $a is 1, see step 1, it will be incremented to 2 and returned;

  • Thus, returning to step 2, the addition operation will be parsed with operands 0 and 2, returned in steps 1 and 3 respectively;

  • The presence of the parentheses in the expression is only to leave the syntax valid, since without them, $a+++++$a , PHP could not correctly verify what the expression is, since the expression that would perceive would be something like $a + ++ ++$a , resulting in a syntax error when trying to evaluate this ++ left over in the expression. So much so that parentheses are unnecessary if properly used blanks, producing exactly the same result:

    $a++ + ++$a
    

    All this can be confirmed by parsing the code with the VLD:

    <?php
    
    $a = 0;
    
    echo $a+++(++$a);
    

    Generating opcodes :

    Finding entry points
    Branch analysis from position: 0
    Jump found. (Code = 62) Position 1 = -2
    filename:       /in/PHp21
    function name:  (null)
    number of ops:  6
    compiled vars:  !0 = $a
    line     #* E I O op                           fetch          ext  return  operands
    -------------------------------------------------------------------------------------
       3     0  E >   ASSIGN                                                   !0, 0
       5     1        POST_INC                                         ~2      !0
             2        PRE_INC                                          $3      !0
             3        ADD                                              ~4      ~2, $3
             4        ECHO                                                     ~4
             5      > RETURN                                                   1
    

    Where to read:

  • In line 3, assignment operation is done from value 0 to address !0 ;
  • In Line 5, it occurs:

    • Post-increment of value in !0 , storing the returned value in ~2 ;
      • !0 becomes 1, returning 0, storing in ~2 ;
    • Pre-increment of value in !0 , storing value in $3 ;
      • !0 becomes 2, returning the value 2, storing in $3 ;
    • Addition between values in% with% and% with%, 0 and 2 respectively, storing the result in% with%;
    • The value of ~2 is passed to the function $3 ;
  • Exactly the same process described above.

    Exactly the same logic occurs when parsing the expression ~4 , such as commented , changing only the addition operation to subtraction, thus resulting 0-2 = -2.

        
    05.08.2017 / 22:52
    7

    Separating the syntax in each expression makes it easy to understand:

    $a = 0;
    $b = $a++;
    $c = ++$a;
    var_dump($a, $b, $c, $b + $c);
    

    See working on ideone . And no PHP Sandbox . Also I placed GitHub for future reference .

    The total expression is composed of an addition of two values, ie the + operator in the middle is the last calculation performed: it is as if it were ($a++) + (++$a) .

    Before he needs to evaluate the expressions that are within the parentheses. An expression takes the value $a and then makes an increment, resulting in 0 since $a is worth 0, but to the thin of the expression $a it counts 1. Then $b is 0 Note the use of the post-increment operator .

    In the other expression it before increments 1 in the value of $a which now counts 1. And since the increment operator not only gives a result, it causes side effects on the variable and changes its value as well, then $a is worth 2. As this time the used operator is pre-increment, the end result is the new value of $a and not the old as occurred in the previous expression. Then $c is equal to 2, as $a .

    Only you are not prompted to print the value of $a , it is printing the result of the sum of the two expressions. In my code I have thrown these values in variables $b and $c to be more visible. And it is the sum of both that is being printed in your code. It is not the value of $a that coincidentally has the same value.

    There are language syntax rules to prioritize what you pick up in the code text and try to form the operators. In addition, the order of execution is determined by precedence and associativity table.

    Victor Stafusa challenged the order I showed, but I did a new experiment and to be sure and hit precedence table . To add 1 in both left ambiguous and gave room for interpretation. I did with and without parentheses and the result was the same. Separating the expressions and executing according to precedence from left to right gives the same result. Already doing from right to left gives another result, since the parentheses can not change the associativity of an operator that is outside them. I could change what's inside. But I think this is another matter, I will not dwell on it.

    Of course the parentheses are necessary in this case to avoid syntax ambiguity, but nothing affects the order of execution.

        
    05.08.2017 / 21:19
    4

    Initial status:

    $a = 0;
    $x = $a+++(++$a);
    

    When the post-increment operation of $a++ is evaluated, $a is still worth 0. We have at this moment:

    $x = 0 + (++$a);
    $a = 1;
    

    When evaluating the pre-increment operation of ++$a , $a is already worth 1. We then:

    $x = 0 + 2; // $x = 2
    $a = 2;
    

    Note that if you invert the expression the answer will still be 2, but the expression values change:

    $a = 0;
    $x = ++$a+$a++;
    

    When the pre-increment operation of ++$a is evaluated, $a becomes valid 1. We have at this moment:

    $x = 1 + $a++;
    $a = 1;
    

    When the post-increment operation of $a++ is evaluated, $a is still worth 1. We then:

    $x = 1 + 1; // $x = 2
    $a = 2;
    

    Now an example with a larger expression. Because $a+++(++$a+$a+++(++$a)) equals 8?

    Initial status:

    $a = 0
    $x = $a+++(++$a+$a+++(++$a));
    

    When the first post-increment operation of $a++ is evaluated, $a is still 0. We have:

    $x = 0 + (++$a+$a+++(++$a));
    $a = 1;
    

    When the next pre-increment operation of ++$a is evaluated, $a is already worth 1. We then:

    $x = 0 + (2 + $a+++(++$a));
    $a = 2;
    

    When the next post-increment operation of $a++ is evaluated, $a is still worth 2. We therefore have:

    $x = 0 + (2 + 2 + (++$a));
    $a = 3;
    

    When the next pre-increment operation of ++$a is evaluated, $a is already worth 3. We finally:

    $x = 0 + 2 + 2 + 4; // $x = 8
    $a = 4;
    
        
    05.08.2017 / 21:36