• 回调函数


    回调函数的原理及PHP实例

    背景:在最近的一个开发项目中,用户要先调用服务才能开始进行一系列的查询活动,想了好久,经同事提醒, 用回调函数即可解决该问题。在这里,对PHP下回调函数的原理及实现分别做一下讲解。

    1 什么是回调

           软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础,因此,下面我们着重讨论回调机制在不同软件架构中的实现。

          对于不同类型的语言(如结构化语言和对象语言)、平台(Win32、JDK)或构架(CORBA、DCOM、WebService),客户和服务的交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。对于一般的结构化语言,可以通过回调函数来实现回调。回调函数也是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数。
    在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象C++或Object Pascal这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。对于分布式组件代理体系CORBA,异步处理有多种方式,如回调、事件服务、通知服务等。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理过程,我们可以通过回调机制来实现。

    2 PHP的回调函数的实现方法


    2.1 全局函数的回调

         这里的全局函数的意思,是直接使用function定义的函数,它不包含在任何对象或类之中。请看下面的例子
    function fnCallBack( $msg1 , $msg2 )
    {
        echo 'msg1:'.$msg1;
        echo "<br /> ";
        echo 'msg2:'.$msg2;

    }

    $fnName = "fnCallBack"; //方法名
    $params = array( 'hello' , 'world' );//传给参数的值

    call_user_func_array( $fnName , $params );

    结果:

    代码说明:
        这里使用了PHP内置的函数call_user_func_array来进行调用。call_user_func_array有两个参数,第1个参数是一个字符串,表示要调用的函数名,第2个参数是一个数组,表示参数列表,按照顺序依次会传递给要调用的函数。

    2.2 类的静态方法的回调
         如果我们要回调的方法,是一个类的静态方法,那怎么办呢?我们依然可以利用PHP内置的call_user_func_array方法来进行调用,请看示例:
    示例代码:
    class MyClass
    {
        public static function fnCallBack( $msg1 , $msg2 )
        {
            echo 'msg1:'.$msg1;
            echo "<br /> ";
            echo 'msg2:'.$msg2;
        }
    }


    $className = 'MyClass'; //类名
    $fnName = "fnCallBack";//类中的方法名
    $params = array( 'hello' , 'world' );//传给参数的值
    call_user_func_array( array( $className , $fnName ) , $params );

    结果:

    代码说明:
        这段代码和第1种方法的代码很相似,我们将类名(MyClass)也作为call_user_func_array的第1个参数传递进去,就可以实现类的静态方法的回调了。注意,这时call_user_func_array的第1个参数是一个数组了,数组的第1个元素是类名,第二个元素是要调用的函数名

    如果我用这种方法调用一个类的非静态方法(也就是把static去掉),会出现什么结果呢?请看下面代码
    class MyClass
    {
        public function fnCallBack( $msg1 , $msg2 )
        {
            echo 'msg1:'.$msg1;
            echo "<br /> ";
            echo 'msg2:'.$msg2;
        }
    }
    $className = 'MyClass';
    $fnName = "fnCallBack";
    $params = array( 'hello' , 'world' );
    call_user_func_array( array( $className , $fnName ) , $params );
    最终运行的结果跟原来一样


    2.3 对象的方法的回调

      我先用最原始的字符串形式的调用方法尝试了一下,如下所示:
    class MyClass
    {
        private $name = 'abc';
        public function fnCallBack( $msg1 = 'default msg1' , $msg2 = 'default msg2' )
        {
            echo 'object name:'.$this->name;
            echo "<br /> ";
            echo 'msg1:'.$msg1;
            echo "<br /> ";
            echo 'msg2:'.$msg2;
        }
    }
    $myobj = new MyClass();
    $fnName = "fnCallBack";
    $params = array( 'hello' , 'world' );
    $myobj->$fnName();

    结果:

    调用是成功了,不过如何把参数params传给这个方法呢,如果把params直接传进去,那么它会作为1个参数,怎么把params拆开来传进去呢?查了下PHP手册,找到了create_function函数,这个方法可以用字符串来创建一个匿名函数,好,有思路了,可以创建一个匿名的函数,在这个匿名函数中,调用我们的回调函数,并把参数传进去。
    我先手动创建一个匿名函数anonymous,在这个函数中,用前面试出来的方法调用回调函数,如下所示:
    class MyClass
    {
        private $name = 'abc';
        public function fnCallBack( $msg1 = 'default msg1' , $msg2 = 'default msg2' )
        {
            echo 'object name:'.$this->name;
             echo "<br /> ";
            echo 'msg1:'.$msg1;
            echo "<br /> ";
            echo 'msg2:'.$msg2;
        }
    }
    $myobj = new MyClass();
    $fnName = "fnCallBack";
    $params = array( 'hello' , 'world' );
    //匿名函数的构建
    function anonymous()
    {
        global $myobj;
        global $fnName;
        global $params;
        $myobj->$fnName( $params[0] , $params[1] );
    }
    anonymous();

    成功了。效果如下:

    参考文献:
    http://myceo.blog.51cto.com/2340655/725411/
    http://blog.chinaunix.net/uid-20684384-id-1895266.html
    http://segmentfault.com/a/1190000002901770

    http://www.abc3210.com/2012/phper_07/php-callback.shtml

    非常感谢以上的参考文献以及博主!

  • 相关阅读:
    视频直播思路
    Swift 算法实战之路:栈和队列
    多线程(RunLoop)
    Charle抓包与wireshark使用
    CoreData归纳使用
    支付宝接入心得(流程)
    TableView的性能优化
    app启动页问题
    公司的开发者账号申请
    java关于时间的笔记
  • 原文地址:https://www.cnblogs.com/lichihua/p/6513240.html
Copyright © 2020-2023  润新知