8

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?

hakre
  • 193,403
  • 52
  • 435
  • 836
ajp5103
  • 111
  • 1
  • 5
  • 3
    You seem to confuse functions with their return values. –  Nov 07 '11 at 17:23
  • I suppose what I wanted was closer to `if ( function() { return false; } () ) {` which is apparently valid in Javascript but not PHP. – ajp5103 Nov 07 '11 at 17:34
  • http://stackoverflow.com/questions/3568410/anonymous-functions-that-execute-immediately call_user_func() is what I was looking for. – ajp5103 Nov 14 '12 at 15:16
  • [PHP Manual: Converting to boolean](http://php.net/language.types.boolean.php#language.types.boolean.casting) – hakre Nov 24 '12 at 20:09

5 Answers5

7

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.

hakre
  • 193,403
  • 52
  • 435
  • 836
3

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

Naftali
  • 144,921
  • 39
  • 244
  • 303
2

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()) { ... }
Marc B
  • 356,200
  • 43
  • 426
  • 500
1

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();
Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
0

You are creating an anonymous function, but never executing it. When you test $q = function() { return 'foo'; }, what you're saying is "Assign a reference to this anonymous function to $q, and pass this test if $q is not null" (isn't PHP fun?)

You need to invoke the closure and assign its result to $q before testing and echoing $q.

Chris Heald
  • 61,439
  • 10
  • 123
  • 137