Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What do PHP closures return in IF statements?

My goal is to put some complex logic in an if() statement. Let's say I have an array of values and I'm going to execute a bit of code if everything in my array is nonzero. Normally, I could say, $valid = true, foreach my array, and set $valid = false when a zero is found. Then I'd run my code if ($valid). Alternatively, I could put my loop into a function and put the function intop my if().

But I'm lazy, so I'd rather not muck about with a bunch of "valid" flags, and I'd rather not write a whole new function that's only being used in one place.

So let's say I have this:

if ($q = function() { return 'foo'; }) {
  echo $q;
}
else {
  echo 'false';
}

I was expecting that the if gets 'foo', which evaluates to true. My closure is committed to $q and the statement executes. $q returns string foo, and 'foo' is printed.

Instead, I get the error Object of class Closure could not be converted to string.

So let's try this instead:

if (function() { return false; }) {
  echo 'foo';
}
else {
  echo 'true';
}

I was expecting that my function would return false and 'true' would be printed. Instead, 'foo' is printed.

What is wrong about the way that I'm going about this? It seems like it's saying, "Yep, that sure is a function!" instead of "No, because the function evaluated to false." Is there a way to do what I'm trying to do?

like image 511
ajp5103 Avatar asked Nov 07 '11 17:11

ajp5103


4 Answers

function() { return false; } creates an object of type Closure, similar to new with other class-types, compare the following code:

$func = function() { return false; };

$func now is an object. Each object returns true in an if clause. So

if ($func)
{
  # true
} else {
  # will never go here.
}

You might want to do this instead:

if ($func())
{
  # true
} else {
  # false
}

which will invoke the Closure object $func and give it's return value.

like image 97
hakre Avatar answered Oct 28 '22 11:10

hakre


Both of those evaluate to true.

You need to make the function execute to use it in the if statement.

Try this:

$q = function() { return false; };
if ($q()) { //should not go here.
  echo $q();
}
else {
  echo 'false';
}

Demo: http://codepad.viper-7.com/Osym1s

like image 29
Naftali Avatar answered Oct 28 '22 12:10

Naftali


PHP's closures are implemented as a hack - objects of type Closure. Your code is actually instantiating an object of this class, and assigning it to $q. In PHP, the result of assignment is the value being assigned, so in effect you code boils down to

if (new Closure()) { ... }
like image 38
Marc B Avatar answered Oct 28 '22 11:10

Marc B


You're not executing the closure when you call echo, thus it's trying to print out the closure, not the result of the closure:

echo $q();
like image 29
Andrew Marshall Avatar answered Oct 28 '22 13:10

Andrew Marshall