我如何在PHP中实现callback?
如何用PHP编写callback?
本手册使用术语“callback”和“可调用”,但是,“callback”传统上指的是一个string或数组值,它像一个函数指针一样 ,引用一个函数或类方法以供将来调用。 这允许自PHP 4以来的函数式编程的一些元素。风味是:
$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');
一般来说,这是使用可调用值的安全方法:
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); }
现代PHP版本允许上面的三个格式直接作为$cb()
被调用。 call_user_func
和call_user_func_array
支持以上所有。
请参阅: http : //php.net/manual/en/language.types.callable.php
备注/注意事项:
- 如果函数/类是命名空间的,则该string必须包含完全限定的名称。 例如
['Vendor\Package\Foo', 'method']
-
call_user_func
不支持通过引用传递非对象,所以你可以使用call_user_func_array
或者在后来的PHP版本中,将callback保存到一个var中,并使用直接的语法:$cb()
; - 具有
__invoke()
方法(包括匿名函数)的对象属于“可调用”类别,可以用同样的方法,但我个人不会将这些与传统的“callback”术语联系起来。 - 传统的
create_function()
创build一个全局函数并返回它的名字。 这是eval()
的包装,而应该使用匿名函数。
使用PHP 5.3,现在可以这样做:
function doIt($callback) { $callback(); } doIt(function() { // this will be done });
最后一个很好的方法来做到这一点。 PHP的一个很好的补充,因为callback是真棒。
callback的实现就像这样完成
// 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');
显示:数据是:这是我的数据
我最近发现的一个漂亮的技巧是使用PHP的create_function()
创build一个匿名/ lambda函数一次性使用。 对于使用callback进行自定义处理的array_map()
, preg_replace_callback()
或usort()
等PHP函数很有用。 它看起来很像它下面的eval()
,但它仍然是使用PHP的一种很好的function风格的方式。
呃…在5.3的地平线上,一切都会好起来,因为在5.3的时候,我们会得到封闭的,并有他们的匿名function
您将需要validation您的通话是否有效。 例如,在特定function的情况下,您需要检查function是否存在:
function doIt($callback) { if(function_exists($callback)) { $callback(); } else { // some error handling } }
在一个类中, create_function
对我不起作用。 我不得不使用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!" ); } } }
然后,使用:
<?php include_once('Dispatcher.php'); $d = new Dispatcher( 'do_callback' ); $d->asynchronous_method(); function do_callback( $data ){ print 'Data is: ' . $data . "\n"; } ?>
[编辑]添加了一个缺less的括号。 另外,添加了callback声明,我更喜欢这种方式。
每当我在php中使用create_function()
,都会畏缩。
参数是一个彗星分离的string,整个函数体中的一个string…呃…我认为即使他们尝试,他们也不能使它变得丑陋。
不幸的是,创build一个命名函数是唯一的select是不值得的麻烦。
对于那些不关心打破与PHP < 5.4
兼容性的人,我build议使用types提示来实现一个更清晰的实现。
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"