首页

文章

PHP中的回调函数是怎么实现的?

发布网友 发布时间:2022-04-19 20:08

我来回答

2个回答

热心网友 时间:2023-06-30 10:30

  前言
  最近在开发一个PHP系统,为了提高系统的扩展性,我想在系统中加入类似Javascript的事件处理机制,例如:我想在一篇新闻被添加以后,我想记录一下日志,用类似Javascript的代码,应该是这样写的:
  function fnCallBack( $news )
  {
  //将$news的信息记录到日志中
  writeLog( $news->getTitle().' has been added successfully!');
  }
  $newsEventManager->addEventListener( 'add' , fnCallBack );
  其中,fnCallBack函数是回调函数,addEventListener表示监听newsEventManager的add事件。当一篇news被add以后,系统就会调用fnCallBack函数,从而完成writeLog的动作。
  但是,PHP中的函数传递方法和Javascript有很大的不同。在Javascript中,函数也是对象,它可以很方便的当作参数传递,但是PHP不行。
  $newsEventManager->addEventListener( 'add' , fnCallBack );
  上面这行代码中的fnCallBack,看上去好像是那个函数的句柄,但实质上它是一个字符串,并不是我们所要的函数。
  为了实现我们的事件模型,有必要研究一下PHP的回调函数的实现方法。
  全局函数的回调
  这里的全局函数的意思,是直接使用function定义的函数,它不包含在任何对象或类之中。请看下面的例子
  示例代码
  function fnCallBack( $msg1 , $msg2 )
  {
  echo 'msg1:'.$msg1;
  echo "<br />\n";
  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个参数是一个数组,表示参数列表,按照顺序依次会传递给要调用的函数。
  效果如下:
  类的静态方法的回调
  如果我们要回调的方法,是一个类的静态方法,那怎么办呢?我们依然可以利用PHP内置的call_user_func_array方法来进行调用,请看示例:
  示例代码:
  class MyClass
  {
  public static function fnCallBack( $msg1 , $msg2 )
  {
  echo 'msg1:'.$msg1;
  echo "<br />\n";
  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个元素是类名,第二个元素是要调用的函数名
  运行结果:
  (其实和第1种方法的结果是一样的 ^_^ )
  继续研究
  如果我用这种方法调用一个类的非静态方法(也就是把static去掉),会出现什么结果呢?请看下面代码
  class MyClass
  {
  public function fnCallBack( $msg1 , $msg2 )
  {
  echo 'msg1:'.$msg1;
  echo "<br />\n";
  echo 'msg2:'.$msg2;
  }
  }
  $className = 'MyClass';
  $fnName = "fnCallBack";
  $params = array( 'hello' , 'world' );
  call_user_func_array( array( $className , $fnName ) , $params );
  运行结果
  和前面的结果还是一样的。。。
  现在我为这个类添加一点属性,并在方法中引用
  class MyClass
  {
  private $name = 'abc';
  public function fnCallBack( $msg1 , $msg2 )
  {
  echo 'object name:'.$this->name;
  echo "<br />\n";
  echo 'msg1:'.$msg1;
  echo "<br />\n";
  echo 'msg2:'.$msg2;
  }
  }
  $className = 'MyClass';
  $fnName = "fnCallBack";
  $params = array( 'hello' , 'world' );
  call_user_func_array( array( $className , $fnName ) , $params );
  运行结果
  出现解析错误,提示$this没有在对象环境下出现,说明这个方法不能用类来调用,而是要用对象来调用。那我们就修改一下代码,创建一个对象:
  class MyClass
  {
  public function fnCallBack( $msg1 , $msg2 )
  {
  echo 'msg1:'.$msg1;
  echo "<br />\n";
  echo 'msg2:'.$msg2;
  }
  }
  $myobj = new MyClass();
  $className = 'myobj';
  $fnName = "fnCallBack";
  $params = array( 'hello' , 'world' );
  call_user_func_array( array( $className , $fnName ) , $params );
  运行结果:
  提示call_user_func_array的第1个参数非法,也就是说,调用失败。看来我们不能用call_user_func_array方法来回调一个对象的方法了,那么如何实现对象方法的回调的?
  对象的方法的回调
  我先用最原始的字符串形式的调用方法尝试了一下,如下所示:
  class MyClass
  {
  private $name = 'abc';
  public function fnCallBack( $msg1 = 'default msg1' , $msg2 = 'default msg2' )
  {
  echo 'object name:'.$this->name;
  echo "<br />\n";
  echo 'msg1:'.$msg1;
  echo "<br />\n";
  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 />\n";
  echo 'msg1:'.$msg1;
  echo "<br />\n";
  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();
  成功了,可以看到,对象的属性name也输出来了
  然后,我用create_function来创建这个匿名函数,同时,代码中的params[0],params[1]应该是动态生成的,代码如下:
  $strParams = '';
  $strCode = 'global $myobj;global $fnName;global $params;$myobj->$fnName(';
  for ( $i = 0 ; $i < count( $params ) ; $i ++ )
  {
  $strParams .= ( '$params['.$i.']' );
  if ( $i != count( $params )-1 )
  {
  $strParams .= ',';
  }
  }
  $strCode = $strCode.$strParams.");";
  $anonymous = create_function( '' , $strCode);
  $anonymous();
  这段代码可以定义一个匿名函数,并保存在$anonymous变量中,最后调用这个$anonymous,实现了方法的回调,如图
  PHP事件模型(观察者模式)的实现思路
  至此,PHP中的3种常见的函数类型(全局函数,类静态函数,对象的方法)都可以回调了,可以实现文章一开始说的事件模型了 :)
  事件模型模仿Firefox的Javascript实现,有3个方法,分别是
  addEventListener:注册一个事件上的响应回调函数
  removeEventListener:删除一个事件上的响应回调函数
  fire:触发一个事件,也就是循环调用所有响应这个事件的回调函数
  不过,由于第2、第3种方法需要传递上下文(也就是类名和对象名),所以addEventListener和removeEventListener应该有3个参数,我是这样设计的:
  function addEventListener( $evtName , $handler , $scope = null )
  第1个参数表示事件名,字符串类型
  第2个参数表示回调函数名,字符串类型
  第3个参数$scope是上下文环境,一共有3种类型,null表示传入的handler函数是一个全局函数,字符串类型表示传入的handler函数是scope类的静态函数,对象类型表示传入的scope是一个对象,handler函数是对象的一个方法。
  function fire( $evtName , $params = null )
  这个方法内,会读取出所有响应evtName的handler,然后判断它对应的scope,如果是null,则用本文第1种方法回调,如果是字符串,则用本文第2种方法回调,如果是对象,则用本文第3种方法回调。这样,一个PHP的事件模型就可以实现了,而且可以将回调函数放在某个对象中。

热心网友 时间:2023-06-30 10:30

call_user_func()
历史要怎么读,有啥诀窍 高中历史诀窍 年终会活动策划方案 深度解析:第一财经回放,探索财经新风向 逆水寒手游庄园怎么邀请好友同住 逆水寒手游 逆水寒不同区可以一起组队吗? 逆水寒手游 逆水寒怎么进入好友世界? 逆水寒手游 逆水寒怎么去别人的庄园? 使用puppeteer实现将htmll转成pdf 内卷时代下的前端技术-使用JavaScript在浏览器中生成PDF文档 【译】将HTML转为PDF的几种实现方案 变形金刚08动画怎么样 变形金刚08动画的问题 变形金刚08动画日语版剧情介绍 高分!换显卡nvidia控制面板被我卸了,重新安装显卡驱动后没了nvidia控... 我的nvidia控制面板被卸载了 怎么找回啊 卸载后 这个画面看着很奇怪_百 ... 李卓彬工作简历 林少明工作简历 广东工业职业技术学院怎么样 郑德涛任职简历 唐新桂个人简历 土地入股的定义 ups快递客服电话24小时 贷款记录在征信保留几年? 安徽徽商城有限公司公司简介 安徽省徽商集团新能源股份有限公司基本情况 安徽省徽商集团有限公司经营理念 2019哈尔滨煤气费怎么有税? 快手删除的作品如何恢复 体育理念体育理念 有关体育的格言和理念 什么是体育理念 万里挑一算彩礼还是见面礼 绿萝扦插多少天后发芽 绿萝扦插多久发芽 扦插绿萝多久发芽 炖牛排骨的做法和配料 网络诈骗定罪标准揭秘 “流水不争先”是什么意思? mc中钻石装备怎么做 为什么我的MC里的钻石块是这样的?我想要那种。是不是版本的问题?如果是... 带“偷儿”的诗句 “君不见巴丘古城如培塿”的出处是哪里 带“奈何”的诗句大全(229句) 里翁行()拼音版、注音及读音 带“不虑”的诗句 “鲁肃当年万人守”的出处是哪里 无尘防尘棚 进出口报关流程,越详细越好。谢谢大家指教。 双线桥不是看化合价升多少就标多少的吗?为什么CL2+2KI=2KCL+I2中I失... 什么是"回调"在C和它们是如何实现的 PHP中的回调函数是怎么实现的? C++中回调函数的如何实现其逻辑? C++回调函数原理 举个简单的小程序例子 回调函数 钩子函数 有什么区别 php回调函数是什么样子的?靠什么原理运行? c#-回调callback是什么原理,机制? C# C++回调函数原理举个简单的小程序例子 回调函数一般都什么作用求解 回调函数(callback)是什么? ,, 关于回调函数的详细讲解 回调函数是怎么实现的?为什么系统就会去调用回调函数 在拼多多上两个人怎么拼单啊 用呼吸作用的原理分析为什么刚采摘下来的苹果最好吃? 人体吸入氧气呼出二氧化碳,这是基于什么原理? 举例说明呼吸作用原理在日常生活中如何被应用 如何运用呼吸作用的原理使农作物保鲜 呼吸作用释放二氧化碳的原理是 光合作用和呼吸作用的原理是什么? 植物呼吸作用的原理 jquery中的回调函数怎么用 回调函数实现通知机制这个怎么理解 函数名作为参数传递与回调函数 回调函数的实现 请问使用回调函数,在接收数据的时候就可以不用判... 讲解如何实现C#回调函数 拼多多上面怎么拼单,毕竟喜欢同一件商品的人很少,QQ群上面拼多多互相砍价群,靠谱吗?请知道的说一说 如何为他人挂号? 怎样在我的手机上给别人挂号挂什么挂? 怎么样可以在微信上给家人预约挂号 南京鼓楼医院在手机上绑定家庭成员后怎么帮家人预... 怎样帮别人在我的手机上给别人挂沈阳医大的号 医院的预约号可以帮别人预约挂号吗? 怎样在我的手机上给别人挂沈阳医大的号 华西医院的微信公众号上怎么帮家人挂号 怎么在手机上挂号预约 拼多多商家如何设置拼单人数? 运维工程师以后的发展方向有哪些? IT运维工程师发展前景如何? 做系统运维工程师有前途吗
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com