96

I was pretty excited to read about anonymous functions in php, which let you declare a variable that is function easier than you could do with create_function. Now I am wondering if I have a function that is passed a variable, how can I check it to determine if it is a function? There is no is_function() function yet, and when I do a var_dump of a variable that is a function::

$func = function(){
    echo 'asdf';
};
var_dump($func);

I get this:

object(Closure)#8 (0) { } 

Any thoughts on how to check if this is a function?

Jage
  • 7,990
  • 3
  • 32
  • 31

5 Answers5

153

Use is_callable to determine whether a given variable is a function. For example:

$func = function()
{  
    echo 'asdf';  
};

if( is_callable( $func ) )
{
    // Will be true.
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Jon Benedicto
  • 10,492
  • 3
  • 28
  • 30
  • 12
    is_callable() will work great whether you're passing in an anonymous function, a function name as a string, or a valid PHP callback array. If you specifically want to check for anonymous functions only, then you would want something like what Gumbo said: make sure the parameter is an object, and make sure it is an instanceof Closure. – Lane Nov 03 '11 at 16:21
  • 2
    What if I want to check wether it's a callack or a string and do different things for them. I don't want a string value to be accidentally taken as a callback. – Gherman Aug 19 '14 at 11:26
  • 3
    @German Just check first if is_string($func) then as second check with is_callable($func) – Heroselohim Jan 08 '15 at 21:48
  • 4
    The code snippet above got me in trouble. I intended a string labeled "Date" and it was then handled as a closure and executed. The correct way is if (($variable instanceof Closure) && is_callable($variable)) {...} – Basil Musa Dec 18 '15 at 12:21
  • @BasilMusa that's because "Date" (`date(...)`) is indeed callable, nothing wrong with that, AFAICS. – Sz. Nov 24 '16 at 17:46
  • Thanks for the bugs. `is_callable` returns true for strings that happen to be function names – Farzher Jan 12 '17 at 02:03
  • For methods, there is also `method_exists()`. – StanE Sep 18 '17 at 20:32
  • 1
    Why instance of closure AND is callable. When is a closure not callable? Wouldn't be surprised if there was a time, but I'm curious why we need both checks. – Joel M Jan 01 '20 at 01:46
  • this is not correct, if you do something as simple as is_callabale('array_slice') it will return true which the variable is clearly NOT a function. – Rob Mar 20 '20 at 06:47
36

You can use function_exists to check there is a function with the given name. And to combine that with anonymous functions, try this:

function is_function($f) {
    return (is_string($f) && function_exists($f)) || (is_object($f) && ($f instanceof Closure));
}
Gumbo
  • 643,351
  • 109
  • 780
  • 844
  • Thanks for this! My app allows users to specify their own hashing function, or alternately provide an argument for hash(). But some of the valid hashing algorithms are also PHP builtins, and therefore callable ('md5', 'sha1' for instance). `is_object()` and `instanceof Closure` is a much more robust way to check for this! – njbair Dec 22 '12 at 18:50
  • Remove the is_string and function_exists calls and this is the function you want to use to detect lambda functions. Thank you! – jack Sep 10 '13 at 13:22
  • @njbair I'm sure you've thought of this, but what if someone specifies something malicious in their own hashing function? – Enigma Plus Mar 11 '21 at 10:20
  • @EnigmaPlus I honestly have no idea what I was working on at the time, but I gather I was working on a library, not an app, and that the hashing function would be specified in-code, not through the frontend by an end-user. – njbair Mar 12 '21 at 14:35
32

If you only want to check whether a variable is an anonymous function, and not a callable string or array, use instanceof.

$func = function()
{  
    echo 'asdf';  
};

if($func instanceof Closure)
{
    // Will be true.
}

Anonymous functions (of the kind that were added in PHP 5.3) are always instances of the Closure class, and every instance of the Closure class is an anonymous function.

There's another type of thing in PHP that could arguably be considered a function, and that's objects that implement the __invoke magic method. If you want to include those (while still excluding strings and arrays), use method_exists($func, '__invoke'). This will still include closures, since closures implement __invoke for consistency.

Brilliand
  • 13,404
  • 6
  • 46
  • 58
  • 8
    This is particularly helpful, because `is_callable()` will try to find a method to call based on a string or array passed, which may autoload classes and may not be the behaviour you expect/require. – spikyjt Feb 16 '15 at 10:12
2
function is_function($f) {
    return is_callable($f) && !is_string($f);
}
  • In future, PHP might change gettype() from Object to Callable, as other languages already do. So, this answer is probably the best way to go. But this can be optimized as: return !is_string($f) && !is_array($f) && is_callable($f). – Alexandre T. Dec 26 '19 at 15:33
0

In php valid callables can be functions, name of functions (strings) and arrays of the forms ['className', 'staticMethod'] or [$object, 'method'], so to detect only functions need to exclude strings and arrays:

function isFunction($callable) {
    return $callable && !is_string($callable) && !is_array($callable) && is_callable($callable);
}
Andrey Izman
  • 1,807
  • 1
  • 24
  • 27