How are callbacks written in PHP?
The manual uses the terms "callback" and "callable" interchangeably, however, "callback" traditionally refers to a string or array value that acts like a function pointer, referencing a function or class method for future invocation. This has allowed some elements of functional programming since PHP 4. The flavors are:
$cb1 = 'someGlobalFunction';
$cb2 = ['ClassName', 'someStaticMethod'];
$cb3 = [$object, 'somePublicMethod'];
// this syntax is callable since PHP 5.2.3 but a string containing it
// cannot be called directly
$cb2 = 'ClassName::someStaticMethod';
$cb2(); // fatal error
// legacy syntax for PHP 4
$cb3 = array(&$object, 'somePublicMethod');
This is a safe way to use callable values in general:
if (is_callable($cb2)) {
// Autoloading will be invoked to load the class "ClassName" if it's not
// yet defined, and PHP will check that the class has a method
// "someStaticMethod". Note that is_callable() will NOT verify that the
// method can safely be executed in static context.
$returnValue = call_user_func($cb2, $arg1, $arg2);
}
Modern PHP versions allow the first three formats above to be invoked directly as $cb()
. call_user_func
and call_user_func_array
support all the above.
See: http://php.net/manual/en/language.types.callable.php
Notes/Caveats:
- If the function/class is namespaced, the string must contain the fully-qualified name. E.g.
['Vendor\Package\Foo', 'method']
call_user_func
does not support passing non-objects by reference, so you can either usecall_user_func_array
or, in later PHP versions, save the callback to a var and use the direct syntax:$cb()
;- Objects with an
__invoke()
method (including anonymous functions) fall under the category "callable" and can be used the same way, but I personally don't associate these with the legacy "callback" term. - The legacy
create_function()
creates a global function and returns its name. It's a wrapper foreval()
and anonymous functions should be used instead.
'someGlobalFunction'
indeed is a defined function. –
Capsulize With PHP 5.3, you can now do this:
function doIt($callback) { $callback(); }
doIt(function() {
// this will be done
});
Finally a nice way to do it. A great addition to PHP, because callbacks are awesome.
Implementation of a callback is done like so
// This function uses a callback function.
function doIt($callback)
{
$data = "this is my data";
$callback($data);
}
// This is a sample callback function for doIt().
function myCallback($data)
{
print 'Data is: ' . $data . "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
Displays: Data is: this is my data
call_user_func()
When they have a syntax which enables them to dynamically call functions and make callbacks. I agree with you! –
Ill One nifty trick that I've recently found is to use PHP's create_function()
to create an anonymous/lambda function for one-shot use. It's useful for PHP functions like array_map()
, preg_replace_callback()
, or usort()
that use callbacks for custom processing. It looks pretty much like it does an eval()
under the covers, but it's still a nice functional-style way to use PHP.
create_function()
? –
Cesaro well... with 5.3 on the horizon, all will be better, because with 5.3, we'll get closures and with them anonymous functions
You will want to verify whatever your calling is valid. For example, in the case of a specific function, you will want to check and see if the function exists:
function doIt($callback) {
if(function_exists($callback)) {
$callback();
} else {
// some error handling
}
}
is_callable( $callback )
–
Towill create_function
did not work for me inside a class. I had to use call_user_func
.
<?php
class Dispatcher {
//Added explicit callback declaration.
var $callback;
public function Dispatcher( $callback ){
$this->callback = $callback;
}
public function asynchronous_method(){
//do asynch stuff, like fwrite...then, fire callback.
if ( isset( $this->callback ) ) {
if (function_exists( $this->callback )) call_user_func( $this->callback, "File done!" );
}
}
}
Then, to use:
<?php
include_once('Dispatcher.php');
$d = new Dispatcher( 'do_callback' );
$d->asynchronous_method();
function do_callback( $data ){
print 'Data is: ' . $data . "\n";
}
?>
[Edit] Added a missing parenthesis. Also, added the callback declaration, I prefer it that way.
For those who don't care about breaking compatibility with PHP < 5.4
, I'd suggest using type hinting to make a cleaner implementation.
function call_with_hello_and_append_world( callable $callback )
{
// No need to check $closure because of the type hint
return $callback( "hello" )."world";
}
function append_space( $string )
{
return $string." ";
}
$output1 = call_with_hello_and_append_world( function( $string ) { return $string." "; } );
var_dump( $output1 ); // string(11) "hello world"
$output2 = call_with_hello_and_append_world( "append_space" );
var_dump( $output2 ); // string(11) "hello world"
$old_lambda = create_function( '$string', 'return $string." ";' );
$output3 = call_with_hello_and_append_world( $old_lambda );
var_dump( $output3 ); // string(11) "hello world"
create_function()
has been DEPRECATED as of PHP 7.2.0. Relying on this function is highly discouraged. –
Cesaro I cringe every time I use create_function()
in php.
Parameters are a coma separated string, the whole function body in a string... Argh... I think they could not have made it uglier even if they tried.
Unfortunately, it is the only choice when creating a named function is not worth the trouble.
create_function()
is now deprecated and should not be used. –
Cesaro © 2022 - 2024 — McMap. All rights reserved.