tags:

views:

351

answers:

1

Forgive me if the title doesn't exactly match what I'm asking, I'm having a tough time describing the question exactly.

Consider the following PHP code:

#!/usr/bin/php
<?php
class foo{
    function bar()
    {
        return true;
    }
}
if (true && $a = new foo() && $a->bar()) {
    echo "true";
} else {
    echo "false";
}

It gives

Fatal error: Call to a member function bar() on a non-object

for the $a->bar(); expression.

Consider the following C code:

int main(void)
{
    int i = 0;

    if (i += 1 && printf("%d\n", i))
    {
     printf("Done: %d.\n", i);
    }
}

It outputs :

0
Done: 1.

Why is this? Since C and PHP claim to short-circuit these expressions and evaluate left to right, I expect a value set in expressions to the left to be used in expressions to the right. Is there something I'm missing?

+7  A: 

Your problem right now is with operator precedence. PHP currently evaluates your PHP statement as such:

if (true && $a = ( new foo() && $a->bar() ) )

In which case $a is not defined by the time you try calling $a->bar().

What you really want is this:

if (true && ( $a = new foo() ) && $a->bar())

Using brackets in complex conditions will prevent those kinds of errors from happening.

EDIT: Proof

if(true && $a = true && false) { }
var_dump($a); // bool(false)

if(true && ( $b = true ) && false) { }
var_dump($b); // bool(true)
Andrew Moore
Same source problem for C.
AProgrammer
+1. Same thing happened to the C code sample. If you put i += 1 in brackets, it does what OP expected.
tsg
Son of a gun, operator precedence never occurred to me. I always thought assignment ops had similar precedence to comparison ops. A quick look at http://us3.php.net/manual/en/language.operators.precedence.php reminded me that I am often mistaken about a great...many...things.
firebird84
No, thoriann, you're wrong. From the other answer that got deleted. This never has a well-defined output: `i = i++ + ++i;` It doesn't depend on threading or not, it is undefined to read and write a variable multiple times in a statement.
GMan
I didn't delete any answers - I guess the poster did. In this case you're both right it looks like, because we looked at the generated assembly and indeed the reads and writes were acting on different values inside the statement, hence why the right-most expressions didn't have the updated values. The operator precedence rules may be a consequence of this, or the other way around, I honestly can't say.
firebird84
Charles Bailey
My previous comment refers to the hypothetical parentesised `(i += 1)` version, obviously.
Charles Bailey
GMan