PHP Oddity: Variable Assigned in Expression Cast as Bool

When blog posts here slow down as they have over the last few weeks, it’s a good bet I have my head down building something.

I ran across an issue today that I’d worked around in the past, but had never explicitly investigated. It appears that when assigning a variable within a multiple condition check in PHP, if you don’t explicitly look for a value the first item in the expression is cast as a bool.

I particularly use this technique a lot in CodeIgniter, for example when pulling data from $this->input->post('foo') – a method that will either return semi-sanitized data from $_POST['foo'] or will return false.

I tested this in PHP 5.3 (built-in version on Snow Leopard).

Here is some sample code that demonstrates this issue, and the workaround.

function foo() {
	return 'foo';
}

function bar() {
	return 'bar';
}

if ($foo = foo()) {
	echo '<p>Condition <code>$foo = foo()</code> passed</p>';
}

var_dump($foo);

echo '<hr />';

if ($foo = foo() && $bar = bar()) {
	echo '<p>Condition <code>$foo = foo() && $bar = bar()</code> passed</p>';
}

var_dump($foo);

echo '<hr />';

if ($foo = foo() && $bar = bar()) {
	echo '<p>Condition <code>$foo = foo() && $bar = bar()</code> passed</p>';
}

echo '<p>$foo:<br />';
var_dump($foo);
echo '<p>$bar:<br />';
var_dump($bar);

echo '<hr />';

if (false !== ($foo = foo()) && $bar = bar()) {
	echo '<p>Condition <code>false !== ($foo = foo()) && $bar = bar()</code> passed</p>';
}

echo '<p>$foo:<br />';
var_dump($foo);
echo '<p>$bar:<br />';
var_dump($bar);

Here is the output of this code:

Condition $foo = foo() passed

string(3) “foo”


Condition $foo = foo() && $bar = bar() passed

bool(true)


Condition $foo = foo() && $bar = bar() passed

$foo:
bool(true)

$bar:
string(3) “bar”


Condition false !== ($foo = foo()) && $bar = bar() passed

$foo:
string(3) “foo”

$bar:
string(3) “bar”

Hopefully this will be useful to someone else when they run across this issue.

Know why PHP works this way? Let me know in the comments.

UPDATE: wrapping each expression in parenthesis works around this. See comments for more detailed explanation.