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

Asked

Viewed 189 times

9

I was playing 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 just came across the code:

$a = 0;

$a+++(++$a)

The "joke" above returned 2.

Why did you return 2? What in detail PHP processed in this sentence?

Test in IDEONE

  • 1

    1 + 1 = 2. No?

  • @Francis yes, but what happens in the syntax?

  • 1

    $a++ is the same thing as $a = $a + 1; The (++$a) also works the same way in this case. In that you add the two and the 2.

  • 1

    Maybe something equally interesting $a++-(++$a); = 2, if analyzing the expression, 1 - 1 = 2 (?)

  • 1

    The manual itself has a very good explanation http://php.net/manual/en/language.operators.increment.php

3 answers

12


The expression PHP perceives will be:

$a++ + (++$a)

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

  1. The operation shall be analysed $a++, producing the present value of $a as a result and then incrementing the variable. That is, 0 is returned and the value of $a becomes 1;

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

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

  4. Thus, going back to step 2, the addition operation will be analyzed with the operands 0 and 2, returned in steps 1 and 3 respectively;

The presence of parentheses in the expression serves only to make the syntax valid, since without them, $a+++++$a, PHP would not be able to correctly measure what the expression is, because the expression you would perceive would be something like $a + ++ ++$a, resulting in syntax error when trying to evaluate this ++ remaining in the expression. So much so that parentheses are unnecessary if properly used blank spaces, producing exactly the same result:

$a++ + ++$a

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

<?php

$a = 0;

echo $a+++(++$a);

Generating the 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:

  1. In row 3, assignment operation is made from 0 to address !0;
  2. In Line 5, occurs:

    • Post-increment of the value in !0, storing the value returned in ~2;
      • !0 becomes 1, returning the value 0, storing in ~2;
    • Increment of the value in !0, storing the value in $3;
      • !0 becomes 2, returning the value 2, storing in $3;
    • Addition between values in ~2 and $3, 0 and 2 respectively, storing the result in ~4;
    • The value of ~4 is passed to the function echo;

Exactly the same process described above.


Exactly the same logic occurs when analyzing the expression $a++-(++$a), as commented, changing only the addition operation to subtraction, thus resulting in 0-2 = -2.

8

If we separate the syntax in each expression it is easy to understand:

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

See working on ideone. And in the repl it.. Also put on the Github for future reference.

The total expression consists of an addition of two values, namely the operator + which is in the middle is the last calculation made: it is as if ($a++) + (++$a).

First he needs to evaluate the expressions that are inside the parentheses. An expression takes the value $a and afterward makes an increment, resulting in 0 since $a 0, but to the fine expression $a is worth 1. Then $b valley 0. Note the use of post-increment operator.

In the other expression he before increments 1 in the value of $a which is now worth 1. And since the increment operator not only gives a result, it causes a side effect on the variable and changes its value as well, then $a is set to 2. Since this time the operator used is pre-incremented, the end result is the new value of $a and no longer the old one as occurred in the previous expression. So $c is worth 2, as well as $a.

Only you’re not having the print value of $a, is printing the result of the sum of the two expressions. In my code I played 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 to take in the code text and try to form the operators. In addition the order of execution is determined by table of precedence and associativity.

Victor Stafusa contested the order I showed, but I did a new experiment and to be right and hit with the precedence table. Adding 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 as the 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 of them. I could change what is inside. But I think this is another matter, I won’t dwell on.

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

  • 2

    In fact the c would be interpreted first because of the parentheses.

  • @Victorstafusa Not in this case as there is no conflict between the precepts of the operators. The execution is exactly what the bigown put (see in 3v4l.org)

  • @Is Victorstafusa sure? Does he ignore the associativity from left to right? I’ve really been in doubt now. If correct, the intermediate result would be different: https://ideone.com/L4AnTG

4

Initial state:

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

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

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

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

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

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

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

When the pre-increment operation of ++$a is evaluated, $a becomes worth 1. We have now:

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

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

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

Now an example with a larger expression. Why $a+++(++$a+$a+++(++$a)) is equal to 8?

Initial state:

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

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

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

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

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

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

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

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

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.