我如何在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_funccall_user_func_array支持以上所有。

请参阅: http : //php.net/manual/en/language.types.callable.php

备注/注意事项:

  1. 如果函数/类是命名空间的,则该string必须包含完全限定的名称。 例如['Vendor\Package\Foo', 'method']
  2. call_user_func不支持通过引用传递非对象,所以你可以使用call_user_func_array或者在后来的PHP版本中,将callback保存到一个var中,并使用直接的语法: $cb() ;
  3. 具有__invoke()方法(包括匿名函数)的对象属于“可调用”类别,可以用同样的方法,但我个人不会将这些与传统的“callback”术语联系起来。
  4. 传统的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

http://wiki.php.net/rfc/closures

您将需要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"