【问题标题】:How do I implement a callback in PHP?如何在 PHP 中实现回调?
【发布时间】:2010-09-08 02:47:18
【问题描述】:

如何用 PHP 编写回调函数?

【问题讨论】:

  • 将另一个 question 链接到这个,因为我试图调用闭包。

标签: php


【解决方案1】:

回调的实现是这样完成的

// 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');

显示:数据是:这是我的数据

【讨论】:

  • 天哪。那是标准吗?太可怕了!
  • 如上所示,还有其他几种方法可以做到这一点。我真的是这么想的。
  • @Nick Retallack,我不明白这有什么可怕的。对于我所知道的语言,例如 JavaScript 和 C#,它们都可以以这种模式构造它们的回调函数。来自 JavaScirpt 和 C#,我真的不习惯 call_user_func()。这让我觉得我必须让自己适应 PHP,而不是相反。
  • @Antony 我反对字符串在这种语言中是函数指针的事实。我在三年前发表了这条评论,所以我现在已经习惯了,但我认为 PHP 是我所知道的唯一一种语言(除了 shell 脚本)。
  • @Antony 我更喜欢使用我在 javascript 中使用的相同语法。所以我什至不明白人们为什么要使用call_user_func(),因为他们有一种语法可以让他们动态调用函数并进行回调。我同意你的看法!
【解决方案2】:

我最近发现的一个绝妙技巧是使用 PHP 的 create_function() 创建一个匿名/lambda 函数以供一次性使用。它对于使用回调进行自定义处理的 PHP 函数(如 array_map()preg_replace_callback()usort())很有用。它看起来很像在幕后执行eval(),但它仍然是使用 PHP 的一种不错的函数式方式。

【讨论】:

  • 不幸的是,垃圾收集器不能很好地处理这种结构,从而产生潜在的内存泄漏。如果您追求性能,请避免使用 create_function()。
  • 您介意使用 PHP 7.4 版本(箭头函数)更新答案并添加关于已弃用 create_function() 的警告吗?
【解决方案3】:

每次我在 php 中使用 create_function() 时都会感到畏缩。

参数是一个逗号分隔的字符串,整个函数体都在一个字符串中......唉......我认为即使他们尝试过也不会让它变得更丑。

不幸的是,当创建命名函数不值得麻烦时,它是唯一的选择。

【讨论】:

  • 当然,它是运行时字符串 eval,因此在编译时不会检查有效语法或其他任何内容。
  • 这个答案在过去 2 年里已经过时了。 create_function() 现已弃用,不应使用。
【解决方案4】:

嗯...随着 5.3 的到来,一切都会更好,因为在 5.3 中,我们将获得闭包和匿名函数

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

【讨论】:

    【解决方案5】:

    您需要验证您的呼叫是否有效。例如,在特定函数的情况下,您将需要检查该函数是否存在:

    function doIt($callback) {
        if(function_exists($callback)) {
            $callback();
        } else {
            // some error handling
        }
    }
    

    【讨论】:

    • 如果回调不是一个函数,而是一个包含对象和方法的数组呢?
    • 或者更确切地说是is_callable( $callback )
    • 这两个都是很好的建议 - 有必要检查您自己的特定实现如何执行回调。我希望警告不要调用不存在的东西导致致命。我让答案更笼统
    【解决方案6】:

    手册交替使用术语“回调”和“可调用”,但是,“回调”传统上是指类似于function pointer 的字符串或数组值,引用函数或类方法以供将来调用。自 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. 如果函数/类是命名空间的,则字符串必须包含完全限定的名称。例如。 ['Vendor\Package\Foo', 'method']
    2. call_user_func 不支持通过引用传递非对象,因此您可以使用 call_user_func_array 或者在以后的 PHP 版本中,将回调保存到 var 并使用直接语法:$cb();
    3. 具有__invoke() 方法的对象(包括匿名函数)属于“可调用”类别,并且可以以相同的方式使用,但我个人不会将这些与旧的“回调”术语联系起来。
    4. 旧版create_function() 创建一个全局函数并返回其名称。它是eval() 的包装器,应该使用匿名函数。

    【讨论】:

    • 确实,使用该函数是正确的方法。在使用变量然后调用它时,正如接受的答案中所建议的那样很酷,它很丑陋并且不能很好地与代码一起扩展。
    • 更改了接受的答案。同意cmets,这是一个很好的答案。
    • 在回答中指出'someGlobalFunction'确实是一个已定义的函数,这对来自Python编程的读者会有所帮助。
    • 从 PHP 5.3 开始,有闭包,请参阅 Bart van Heukelom's answer。它比所有这些遗留的混乱更简单和“标准”。
    • 是的,我在回答中提到了匿名函数,但 OP 要求“回调”(在 2008 年),这些老式回调仍然在大量 PHP 代码库中大量使用。跨度>
    【解决方案7】:

    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";
    }
    ?>
    

    [编辑] 添加了缺少的括号。 另外,添加了回调声明,我更喜欢这样。

    【讨论】:

    • Dispatcher 类不需要 $this->callback = $callback 的属性才能工作吗?
    • @james poulson:PHP 是一种动态语言,所以它可以工作。但我很懒惰。我通常会声明属性,让每个人的生活更轻松。你的问题让我再次查看该代码并发现语法错误,你。谢谢
    • 我不知道这是可能的。感谢您的回答:)。
    • 在创建 Dispatcher 对象并调用异步方法之前声明 do_callback 函数不是更安全吗?
    【解决方案8】:

    使用 PHP 5.3,您现在可以这样做:

    function doIt($callback) { $callback(); }
    
    doIt(function() {
        // this will be done
    });
    

    终于找到了一个不错的方法。 PHP 的一个很好的补充,因为回调很棒。

    【讨论】:

    • 这必须是最佳答案。
    【解决方案9】:

    对于那些不关心破坏与 PHP &lt; 5.4 的兼容性的人,我建议使用类型提示来进行更简洁的实现。

    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() 自 PHP 7.2.0 起已弃用。强烈建议不要依赖此函数。
    猜你喜欢
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 2017-04-25
    • 2016-04-10
    • 2018-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多