Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding assignment inside condition solving precedence [closed]

Today at work I got stucked in a line of code I can't achieve to understand. I had a function in JavaScript that, to ensure getting an unique timestamp did that ugly loop:

var ts = +new Date();
while (ts === (ts = +new Date()));

I think it's clear to understand that we're re-setting ts until it's value becomes different.

But when I tried to migrate the function to PHP code - like that:

$ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime());
//regex extracts digits and re-positions them - ugly microtime :(
while ($ts === ($ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime())));

interpreter enters an infinite loop. All my tries seemed to point that $ts assignment is taking place before comparison, but I can't understand why left-side expression isn't being resolved first. My PHP knowns are not as big as my JavaScript ones, so I'm wondering if there is some key tip about PHP expressions and statements I'm leaking.

Advice: I don't want to fix my code by making a "well constructed" loop - the solution is obvious - I'd love to understand what's happening here. All help is much appreciated.

like image 645
Áxel Costas Pena Avatar asked Jun 20 '26 07:06

Áxel Costas Pena


2 Answers

PHP needs the assignment to be evaluated first, before a comparison can be made. Normally, the assignment operator would have a very low precedence, so when you write $a = $b + $c, the addition is calculated first, before the result is assigned to $a. However, it is a special case, and although it doesn't seem to be documented very well, a similar case is found in the documentation, stating:

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.

So in this case, PHP determines that it needs to do the assignment before it can negate the result of the assignment. I think a similar thing is happening here, although you're right that PHP should be able to do the assignment later.

Actually, the result might be unpredictable, as is the case with some other expressions:

// mixing ++ and + produces undefined behavior
$a = 1;
echo ++$a + $a++; // may print 4 or 5
like image 57
GolezTrol Avatar answered Jun 23 '26 02:06

GolezTrol


PHP will evaluate the assignment before the comparison, so by the time it does $ts ===, $ts = has already happened. Here's a quick fix:

$ts = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime());

//regex extracts digits and re-positions them - ugly microtime :(
while ($ts === ($ts2 = preg_replace('/^\d\.(\d+)\s(\d+)$/', '$2$1', microtime()))) {
    $ts = $ts2;
}

Also, PHP has a handy function called uniqid() that will do something similar for you. It will give you a unique string every time.

like image 24
Jonathan Amend Avatar answered Jun 23 '26 02:06

Jonathan Amend