Yes, there is... even though it's a horrid, horrid hack:
$foo = new Foo();
function makeCallable($instance, $method)
{
return function() use ($instance, $method) {
return $instance->{$method}();//use func_get_args + call_user_func_array to support arguments
};
}
Then you can use:
$callable = makeCallable($foo, 'bar');
var_dump(is_array($callable));//false
The downside is that:
var_dump($callbale instanceof Closure);//true
Basically, don't pay any attention to the fact that your callable is also an array, and just use type-hinting throughout your code base:
function foobar(callable $action)
{
return call_user_func($action);
}
That ought to work just fine.
On why you feel the current callable array is a downside: I understand why you feel this is not a good thing. There is indeed no need for anyone to know that a particular callable construct is an array, or a string, or an anonymous function (which is actually an instance of the Closure
class - another implementation detail you might not want to pass around). But it's exactly because callable constructs come in many forms, the callable
type-hint exists: the code you write that requires a callable needn't care about how that callable entity is implemented, it just needs to know that it can call that piece of information:
function handleEvent(callable $action, array $args = null)
{
if ($args) {
return call_user_func_array($action, $args);
}
return call_user_fun($action);
}
No need for me to check if $action
is a string (like 'strtolower'
, a Closure
instance or an array) I just know I can call it