PHP回调函数的几种用法
PHP回调函数的实现方法
目录
前言
全局函数的回调
类静态函数的回调
对象的方法的回调
PHP事件模型(观察者模式)的实现思路
前言
最近在开发一个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,在这个函数中,用前面试出来的方法调用回调函数,如下所示:
] );
}
anonymous();成功了,可以看到,对象的属性name也输出来了
然后,我用create_function来创建这个匿名函数,同时,代码中的params[0],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的事件模型就可以实现了,而且可以将回调函数放在某个对象中。
目前,PHP的最新发布版本是5.2.9,5.3版本开始加入了函数闭包等概念,会使函数的传递更加的方便,到时候,PHP将会更加灵活和优美,期待一下吧~
Ferris Xu
2009年04月21日
posted on 2009-04-21 16:52 CoffeeCat 阅读(10873) 评论(5) 编辑 收藏 引用
PHP回调函数的几种用法的更多相关文章
- C++ 回调函数的定义与用法
一回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函 ...
- 关于transition回调函数的几种写法
平时工作中经常遇到需要transition动画结束后触发某个功能的问题,但是在映像中好像只见过animate的回调函数, 而transition的很多属性无法在animate中使用,经过一些总结归纳, ...
- C++ 回调函数的几种策略
Stackoverflow中提出了这样一个问题:假设我们实现了一个User类,Library类,现在Library类中utility需要回调User中func方法,总结答案,常见的几种方法如下: 静态 ...
- getline()函数的两种用法
getline()函数的输入流对象可以是标准输入流对象cin,也可以是一个文件输入流对象fin; (1)输入流对象的成员函数(有三个参数,一般除非需要自己选定停止符,并不推荐使用): basic_is ...
- jQuery中$()函数的7种用法汇总
前言 jQuery对象是一个类数组的对象,含有连续的整形属性以及一系列的jQuery方法.它把所有的操作都包装在一个jQuery()函数中,形成了统一(也是惟一)的操作入口.其中我们用的非常频繁的一个 ...
- JS函数的几种用法
1.正常使用:
- Shell函数的7种用法介绍
1. 在shell文件内部定义函数并引用: 复制代码代码如下: [~/shell/function]# cat factorial.sh #!/bin/bashfunction factorial{f ...
- decode函数的几种用法
1:使用decode判断字符串是否一样 DECODE(value,if1,then1,if2,then2,if3,then3,...,else) 含义为 IF 条件=值1 THEN RETURN(va ...
- Mysql中decode函数的几种用法
1.使用decode判断字符串是否一样 decode(value,if1,then1,if2,then2,if3,then3,...,else) 含义为 IF 条件=值1 THEN RETURN(va ...
随机推荐
- CodeForces 577B 模和vecto
上一年的最后一次训练赛被卡了AK... 一开始天真的认为每个数字都进行取模 然后认为它是一个vol为取模后的数 val为0的01背包 去计算dp[m]能否被装满 只想到了其中的一点..简直天真 后来看 ...
- slf4j提示Class path contains multiple SLF4J bindings
报错: SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding .jar!/org/slf4j/impl/St ...
- XPath学习:parent,child
XPath 是一门在 XML 文档中查找信息的语言.XPath 可用来在 XML 文档中对元素和属性进行遍历. XPath 是 W3C XSLT 标准的主要元素,并且 XQuery 和 XPointe ...
- mysql默认字符集修改
(1) 最简单的修改方法,就是修改mysql的my.ini文件中的字符集键值,添加 [mysql] default-character-set = utf8 [mysqld] character_se ...
- 不绑架输入--document.getElementById("linkage_"+id_type+"_echo").value="";--联动
<script> function w_linkage(id_type) { var selected = $("#linkage_"+id_type+"_t ...
- https://github.com/akullpp/awesome-java
java stack https://github.com/akullpp/awesome-java
- 【No.1】监控Linux性能25个命令行工具
如果你的Linux服务器突然负载暴增,告警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?通过以下命令或者工具可以快速定位 top vmstat lsof tcpdump netsta ...
- Groovy 在eclipse中的使用
今天在写Groovy脚本的时候发现一个问题.如下图,element的elementIterator()方法不能智能显示,只能手动输入.而在eclipse中如果类a没有方法a,那么你是用"cl ...
- hadoop、hbase、hive、zookeeper版本对应关系
本文引用自:http://www.aboutyun.com/blog-61-62.html 最新版本: hadoop和hbase版本对应关系: Hbase Hadoop 0.92.0 1.0.0 ...
- C# where(泛型类型约束)
/*在泛型类型定义中,where 子句用于指定对下列类型的约束:这些类型可用作泛型声明中定义的类型参数的实参. 例如,可以声明一个泛型类 MyGenericClass,这样,类型参数 T 就可以实现 ...