12

In this statement:

1 + $newVar = 200;

$newVar gets created and assigned the value of 200. How does this work? Precedence rules show that the addition takes place first, before the assignment. I can't wrap my head around this. How does the assignment take place if the variable is evaluated with the + operator first?

PHP provides this little nugget. Does this mean these rules apply except when they don't?

Note:

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.

Evil Elf
  • 2,157
  • 3
  • 22
  • 28
  • Maybe I'm missing something but the addition is taking place before the assignment, no? http://sandbox.onlinephpfunctions.com/code/968993816a230e4c97e9d3e2bf5bed326deda590 – waterloomatt May 11 '18 at 19:21
  • 2
    Where do you see `200.00`? `var_dump( $newVar );` shows `int(200)` in PHP 7.2.4. Please consider adding more context to your question as your described behavior is not reproducible. – MonkeyZeus May 11 '18 at 19:21
  • Hmm, I wrongly assumed the I am reading worked. I apologize. My question still remains about how is variable assigned if the left side of the assignment evaluates first? – Evil Elf May 11 '18 at 19:27
  • @waterloomatt, that example is perfect. How does that not boil down to `1 + $newVar = 200`, then `1 = 200`? – Evil Elf May 11 '18 at 19:29
  • 1
    I *think you're misreading that. It is `1 + $var;` and then `$var = 200;` – waterloomatt May 11 '18 at 19:33
  • [Check this](https://tio.run/##K8go@P/fxr4go4DL1EBBW0ElL7U8LLFIwVbByMDAmis1OSMfJgblKXEpWXNxmZGi2EDPAAhI0KCUlp@vkJRYpKSH0KEE1KKER4@9HReXjb2tgiHEmrLEIluwJf//AwA) The assignment occurs, the operation? unless you "echo the operation" it's shown. – Francisco Hahn May 11 '18 at 19:35
  • Thank you @waterloomatt. That makes sense. But why does the `(x + y)` not evaluate to a value first instead of allowing the variable to be left standing for the assignment? – Evil Elf May 11 '18 at 19:38
  • 2
    I thought that associative properties only broke ties between operators of the same precedence. – Evil Elf May 11 '18 at 20:54
  • You're right. This is some exception to the rule, not caused by associativity @WOUNDEDStevenJones – Paul May 11 '18 at 21:00
  • @EvilElf ah you're right (associative :P) "When operators have equal precedence their associativity decides how the operators are grouped." – WOUNDEDStevenJones May 11 '18 at 21:02
  • Related: https://stackoverflow.com/questions/33349790/php-operator-precedence-bug – Paul May 11 '18 at 21:49

3 Answers3

3

In this instance, it would not make sense for PHP to evaluate the arithmetic expression before the assignment, as arithmetic operator returns a value and you can't assign a value to a value. So it seems like PHP breaks its rules a bit in this case and does the assignment first.

Some code to show assignment is taking place first:

$nVar = 0;
echo (1 + $nVar = 200);     //201
echo $nVar;    //200

If the + occurred first (and somehow was legal and made sense), they would both echo 200, because (1 + $nVar) does not set $nVar to 1, and you would get the result of the assignment.

Check out this example as well:

$nVar = true;
echo (!$nVar = false);  // true | 1
echo '<br/>br<br/>';
var_dump($nVar);        // false

! has higher precedence and is also right associative, yet assignment still evaluates first.

Nick Rolando
  • 25,879
  • 13
  • 79
  • 119
1

How does the assignment take place if the variable is evaluated with the + operator first?

The + operator is not necessarily evaluated first and the docs are pretty clear about this

Operator precedence and associativity only determine how expressions are grouped, they do not specify an order of evaluation. PHP does not (in the general case) specify in which order an expression is evaluated and code that assumes a specific order of evaluation should be avoided, because the behavior can change between versions of PHP or depending on the surrounding code.

And testing a few scenarios on a different versions it becomes clear that the assignment operator is evaluated first (as you observed), since evaluating the + operator first would throw a parse error:

(1 + $n) = 200;

PHP Parse error: syntax error, unexpected '=' in php shell code on line 1

If you want to be sure of how this will execute across versions, best practice would be to provide more explicit grouping for your desired results - for example:

1 + ($n = 200);
  • 1
    The order of evaluation has nothing to do with this. Precedence rules mean that it is grouped as `(1 + $n)`, but of course PHP is making an exception to those rules because that doesn't make sense as the lefthand side of an assignment. When the docs say the order of evaluation is unspecified that is about whether `a()` or `b()` is called first in `a() + b()`, and not about how expressions are grouped. The section you quoted even says that precedence and associativity determine how the expressions are grouped. – Paul May 11 '18 at 19:56
  • @Paulpro Hmm but in the doc where it mentions the order of evaluation, the given example is `$a = 1;` and `echo $a + $a++; // may print either 2 or 3`, which has nothing to do with `a()` or `b()` no? – Chin Leung May 11 '18 at 20:01
  • @ChinLeung That has everything to do with it. Just substitute `a()` for `$a` and `b()` for `$a++`. It's saying the left operand of `+` may be evaluated before or after the right operand. That's not unique to the `+` operator. The order that the operands are evaluated in is unspecified, but that's not related to operated precedence or the way the expression is grouped. – Paul May 11 '18 at 20:04
  • @ChinLeung Left associativity and equal precedence of `+` and `-` just means that `a - b + c` is evaluated as `(a - b) + c` and not as `a - (b + c)` which would have different results. The order that the subexpressions `a`, `b`, and `c` are evaluated in is not specified. so `$a = 0; echo $a++ - $a++ + a++` could result in several different values as there are six possible orders the postincrements could happen in, but due to left associativity it will always be grouped as `echo ($a++ - $a++) + a++;` and never `echo $a++ - ($a++ + a++);`. – Paul May 11 '18 at 20:05
  • 1
    @Paulpro - perhaps I misunderstood the docs, but you are wrong to say "*This answer has very little to do with the question*". I can see how you are interpreting it, but imo, the docs are at best ambiguous and at worst completely wrong here if what you are saying is true and it's merely an *exception*. I fail to see how what I posted is unrelated. – But those new buttons though.. May 11 '18 at 20:08
  • At the very least, I've demonstrating the parse error that would happen if you group `(1 + $n)` and encouraging the OP to be more explicit has to count for something and is certainly related to the question. – But those new buttons though.. May 11 '18 at 20:10
  • You have demonstrated that, but the question itself is actually quite interesting and you haven't answered it. – Paul May 11 '18 at 20:14
  • Good doc reference, seems very related to me. – Nick Rolando May 11 '18 at 21:28
  • @NickRolando Then you do not understand the differences between precedence, associativity, and order of evaluation. They are three different things. The question is about precedence and the doc reference is about unspecified order of evaluation, which doesn't have anything to do with precedence and doesn't answer the question. The `"Note"` from that page that the OP quoted is much more relevant, but unfortunately is just a note and doesn't explain the actual rules of the language. – Paul May 11 '18 at 21:33
  • @Paulpro Ah I see what you're saying now about order of eval. – Nick Rolando May 11 '18 at 21:49
  • @NickRolando Yeah, I think it just comes down to your first sentence, although the docs don't make it clear. Most operators can have arbitrary expressions for each of their operands, but not all. Any assignment operator, `++`, `--`, and prior to PHP 5.4 array access operators each have one operand that cannot be an arbitrary expression, so the parser doesn't follow the precedence rules in those cases. – Paul May 11 '18 at 21:59
  • 1
    @NickRolando The handling is quite different from other languages though. In JavaScript `1 + x = 5` throws a ReferenceError and in `C` it won't compile. It is interesting that PHP ignores the precedence rules if it would lead to an error and just finds another way to parse it instead. – Paul May 11 '18 at 22:05
1

I'm not entirely sure about this answer. Someone could help me here if knows better.

This file is from PHP source (https://github.com/php/php-src/blob/eb39d8d6863ab1f327417b274fed7a41b58daf1e/Zend/zend_language_parser.y)

If you take a look, this is the point where the interpreter evaluates the expression.

At the first time, it will fetch the number 1, then + sign, that evaluates to expr '+' expr (link).

Next time, the second expr is evaluated as variable '=' expr ($newVar = 200) (link). By solving that, internally, will do

expr(1) + expr($newVar = 200)
expr(1) + expr($newVar(200))
201

If you do echo (1.00 + $newVar = 200); it will output 201, but $newVar got 200;

Felippe Duarte
  • 14,901
  • 2
  • 25
  • 29