call_user_func('a_callback_function');
call_user_func(array('AClass', 'aCallback'));
call_user_func(array($obj, 'aCallback'));
$callback = 'a_callback_function';
$callback();
$callback = array($obj, 'aCallback');
$callback();
What can we use this for? The most obvious and straight forward this is a lightweight state pattern implementation -
$a_thing()
Will behave differently depending on the value of the $a_thing variable, it's state. Another way to look at php callbacks is as proxies for 'real' functions, class or object methods.
Oh, let's not forget is_callable, it's a very useful little number.
The facility of PHP objects to encapsulate a state and us being able to access this state later can be used to turn them into functions. Let's consider:
class aClass{
var $state;
function get() { return $state; }
function next() { $state=random; }
function callbacks() { return array( array($this,'get'), array($this, 'next'));}
}
$obj = new aClass();
list( $random, $next_random ) = $obj->callbacks();
echo $random();
echo $next_random();
This laboured example shows how to lift the callback definitions from within the object to a different scope. What is interesting to note is that $random() and friend live live in a different scope from the object, at least at first glance, but maintain their state in the object scope.
We can use the above observation to create scoped functions using the technique described in state and closures. The real downside of this method is that the code is not readable and we need to keep a lot in our heads.
Combining the php closures with first class functions (callbacks) gives us better readability at the application point, without sacrificing power.
An interesting way to improve the readability of code using lexical closures is to employ some meta-programming techinques.
My personal favourite is hinted in the list style in php writeup". Improving on that technique can lead us to be able to define lexically scoped functions without too much overhead, while maintaining readable, albeit in unusual for php style, code. Something like
defun( a_name,
args(),
begin(
$do_something,
$do_something_else,
...))
)
The downside if this method is the execution speed. If speed is required, one should be able to lift these definitions into proper php, so that none of the meta functions are used.