Jump to content

is this a bug or feature?


sneskid

Recommended Posts

(v5.1.4)

function xyz(&$v){$v++;return $v;}
$a = array();
$b=0;
$a[$b] = $b++; // [1]=>int(0)
$a[$b] = ++$b; // [2]=>int(2)
$a[$b] = xyz($b); // [3]=>int(3)
$a[$c=$b] = xyz($b); // [3]=>int(4)  $c negates the bug|feature
var_dump($a);

 

When $b is altered on the right side, it alters the expected assign-to index of $a on the left side.

This shows that the left side evaluation can be effected after the right side evaluation.

In other languages, for example Javascript, $a[$b] would have first been evaluated&locked as $a[0].

Link to comment
Share on other sites

OK, now you've got me testing, and I'm really confuzzled ;) ... Compare the following and tell me which logically would come first:

<?php
// Test one
$a = array();
$b = 0;
$a[$b++] = $b;
// Outcome: "[0] => int(1)"

// Compare to test two
$a = array();
$b = 0;
$a[$b] = $b++;
// Outcome: "[1] => int(0)"
?>

 

My guess was that the first result would be exactly what it is since the key would increment the variable before it is used on the right side of the assignment. However, the second test still has me confused. I thought it would be [0] => int(0), but $b would be incremented to '1' after the assignment.

 

I'm very interested to get other people's input on this. It does seem inconsistent to me as well.

Link to comment
Share on other sites

php -v 4.3.10

 

I got exactly as you would expect.

 

<?php

  $a = array();
  $b = 0;
  $a[$b++] = $b;
  print_r($a)."\n";
  echo $b."\n\n";

  $a = array();
  $b = 0;
  $a[$b] = $b++;
  print_r($a)."\n";
  echo $b."\n\n";

?>

 

Produced....

 

Array
(
    [0] => 1
)
1

Array
(
    [0] => 0
)
1

Link to comment
Share on other sites

Most languages leave such obscure questions undefined.  Just don't do it :)  Your code may work for this version of php, but there's no guarantees it will work next version.

 

The same goes for function calls like

 

f($b++, $b++);

Link to comment
Share on other sites

Here's another one for you..

 

$i = 7;
print ($i-- * $i++) . "\n";
$i = 7;
print ($i++ * $i--) . "\n";

 

Here in php 4.3.10 and 5.1.4 I get this output:

 

42

56

 

And here's another oddity I found while wondering why my sorting wasn't working properly

 

if ("2" < "10") print "2 < 10\n";
if ("10" < "10a") print "10 < 10a\n";
if ("10a" < "2") print "10a < 2\n";

 

This shows that a < b < c < a, which gives a loop in the ordering :P

Link to comment
Share on other sites

Here's another one for you..

 

$i = 7;
print ($i-- * $i++) . "\n";
$i = 7;
print ($i++ * $i--) . "\n";

 

Here in php 4.3.10 and 5.1.4 I get this output:

 

42

56

 

And here's another oddity I found while wondering why my sorting wasn't working properly

 

if ("2" < "10") print "2 < 10\n";
if ("10" < "10a") print "10 < 10a\n";
if ("10a" < "2") print "10a < 2\n";

 

This shows that a < b < c < a, which gives a loop in the ordering :P

 

Those don't necessarily strike me as odd. The first one, especially: if you get 42 and 56, that's exactly how you would expect those increment and decrement operators to work. Remember that when the inc/dec operators come after the variable that the value is used first and then the operation is carried out, so your first example would be figured as follows ($i-- * $i++):

$i returns 7 to the equation then decrements itself leaving us with 7 * __. Then, $i returns 6 to the second value and increments itself afterwards giving us 7 * 6 and leaving $i with a value of 7 once again. The reverse is true of the second line giving you 7 * 8 and $i with the value of 7. So, you should get 42 and 56 as your answers.

 

With the other, your comparisons will be implicitly converted to integer comparison when your strings contain only numbers. When they contain alpha characters as well, they will have a string comparison. I'm not sure if that's exactly the best way to state it, but it makes sense that it would come out the way you're showing.

Link to comment
Share on other sites

But who said expressions should be evaluated left to right?  And who specified when the pre and post increment should be done?  These things are left unspecified in PHP, so the result could be anything.  The possibilities are:

 

6*6 (decrement, take left value, take right value, increment)

6*7 (decrement, take left value, increment, take right value)

7*7 (take left value, take right value, decrement, increment)

7*8 (take left value, increment, take right value, decrement)

 

All are quite valid way of interpreting the expression.

 

Regarding the sorting, yes it does have logic behind it, it's just not the logic you might expect :)  Here's the details (I made a journal post about it a while back)

 

"2" < "10" - integer comparison

"10" < "10a" - string comparison. Longer string wins.

"10a" < "2" - string comparison. "2" wins because only the first characters are compared in this case.

Link to comment
Share on other sites

But who said expressions should be evaluated left to right?  And who specified when the pre and post increment should be done?  These things are left unspecified in PHP, so the result could be anything.

 

Not true at all... Read the manual about increment and decrement operators. There are "pre" and "post" increment and decrement operators that are very clearly documented: not to mention this is something that is cross-language accurate, so it goes beyond simply PHP to a programming theory now. If you use the post increment operator, as you have, you will see on the page I cited that the value of the variable is very clearly used before the increment takes place, and the variable is immediately incremented/decremented as soon as that value is returned.

 

As for expressions being evaluated left to right, now you're questioning basic math ;) ... Of course, you do have to take into account operator precedence, but once that is settles, each operation individually is always handled left to right.

 

So, with these principles in place, "7 * 6" and "7 * 8" are the only logical choices to do the math.

 

As far as the Math operators go, I love this quote:

Remember basic arithmetic from school? These work just like those.

Link to comment
Share on other sites

The documentation says that PHP supports C-style pre-increment and post-increment operators.. and C's pre and post increment have exactly the problem I'm describing.  It is certainly not cross-language accurate!  Far from it, these operators behave differently between compilers and languages.

 

The documentation states "Returns $a, then increments $a by one." for post-increment.  It doesn't say immediate, which is exactly what causes compiler-dependent behaviour in C.  The increment will happen before the next statement, but will it happen before evaluation of other children of the current expression is complete?  In the absence of anything specific, you might assume that the rules are the same as those in C, where the operators came from.

 

As for left to right evaluation, basic math doesn't specify left to right evaluation.  Basic math does say that you can switch the left and right arguments of * and your result will be identical.  In the example, switching the left and right arguments changes the result.

 

Edit: Here's a summary of the problem in C: http://c-faq.com/expr/evalorder2.html

Link to comment
Share on other sites

I've always been raised to believe ( I make it sound religious almost ) that:

 

x++ means:

take x as is, at this moment in time (not later) and apply that value in the current operation (one would expect the compiler to be using temporary variables at this point) THEN immediately increment it by 1. THEN continue with the rest of the operation.

 

++x means:

increment x by 1 NOW, THEN use the new value, THEN continue the operation.

 

operation: be it arithmetic, function calls, array index assignments, echo messages, whatever.

 

Thus 42 and 56 are as expected.

and

$x=1;

echo add($x++,$x++);

should echo 3 and leave $x as 3. (and it does, yay)

 

But I'm sure we can all agree that

$x=1;

$a[$x] = $x++;

should be $a[1] = 1 NOT $a[2] = 1; (which I would accept if this was legal: $a[&$x] = $x++;)

and leave $x=2

 

So 4.3.10 has it right, and 5.1.4 got lazy?

This behavior says "yea, I'll check that variable later, saves memory, PHP is way too bloated... who cares about the foundation of programming as we know it." and I have an issue with that, the kind of issue that makes me want to divorce PHP and marry Perl.

Link to comment
Share on other sites

The documentation states "Returns $a, then increments $a by one." for post-increment.  It doesn't say immediate, which is exactly what causes compiler-dependent behaviour in C.  The increment will happen before the next statement, but will it happen before evaluation of other children of the current expression is complete?  In the absence of anything specific, you might assume that the rules are the same as those in C, where the operators came from.

OK, I agree with that statement. I was approaching from a logical perspective assuming that at the time the variable was accessed, it is incremented/decremented. You are correct that it is not explicitly stated that it is immediate.

 

As for left to right evaluation, basic math doesn't specify left to right evaluation.  Basic math does say that you can switch the left and right arguments of * and your result will be identical.  In the example, switching the left and right arguments changes the result.

 

Edit: Here's a summary of the problem in C: http://c-faq.com/expr/evalorder2.html

Oh, contrair... ;) ... Basic math tells us to follow the precedence of the operators as far as you can, and then move across the equation from left to right for the solution. Yes, with multiplication you happen to have the same solution if you switch your multiplicands (as with addition), but with subtraction and division, this is not the case, therefore, we follow some basic principles and move from left to right. Nobody in their right mind would try to argue that "4 - 3" could be either 1 or -1 since you could go from right to left. It's the exact same principle with all basic math operators.

 

I actually wrote into the bug reporting for this to see what input I would get back from the "official" guys, and here's the response I got:

Using and modifying the same variable when using post/pre-

decrement/increment is undefined (and not only in PHP).

Very helpful, huh? lol.

 

btherl, I think we're back to your original recommendation being the most useful comment in this thread so far:

Most languages leave such obscure questions undefined.  Just don't do it :)

 

Thanks ;)

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.