PHP回调函数与匿名函数实例详解


Posted in PHP onAugust 16, 2017

本文实例讲述了PHP回调函数与匿名函数。分享给大家供大家参考,具体如下:

回调函数和匿名函数

回调函数、闭包在JS中并不陌生,JS使用它可以完成事件机制,进行许多复杂的操作。PHP中却不常使用,今天来说一说PHP中中的回调函数和匿名函数。

回调函数

回调函数:Callback (即call then back 被主函数调用运算后会返回主函数),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。

通俗的解释就是把函数作为参数传入进另一个函数中使用;PHP中有许多 “需求参数为函数” 的函数,像array_map,usort,call_user_func_array之类,他们执行传入的函数,然后直接将结果返回主函数。好处是函数作为值使用起来方便,而且代码简洁,可读性强。

匿名函数

匿名函数,顾名思义,是没有一个确定函数名的函数,PHP将匿名函数和闭包视作相同的概念(匿名函数在PHP中也叫作闭包函数)。它的用法,当然只能被当作变量来使用了。

PHP中将一个函数赋值给一个变量的方式有四种:

① 我们经常会用到的:函数在外部定义/或PHP内置,直接将函数名作为字符串参数传入。注意:如果是类静态函数的话以CLASS::FUNC_NAME的方式传入。

② 使用create_function($args, $func_code);创建函数,会返回一个函数名。 $func_code为代码体,$args为参数字符串,以','分隔;

③ 直接赋值:$func_name = function($arg){statement}

④ 直接使用匿名函数,在参数处直接定义函数,不赋给具体的变量值;

第一种方式因为是平常所用,不再多提;第二种类似eval()方法的用法,也被PHP官方列为不推荐使用的方式,而且其定义方式太不直观,我除了测试外,也没有在其他地方使用过,也略过不提。在这里重点说一下第三种和第四种用法;

后两种创建的函数就被称为匿名函数,也就是闭包函数, 第三种赋值法方式创建的函数非常灵活,可以通过变量引用。可以用 is_callable($func_name) 来测试此函数是否可以被调用, 也可以通过$func_name($var)来直接调用;而第四种方式创建的函数比较类似于JS中的回调函数,不需要变量赋值,直接使用;

另外要特别介绍的是 use 关键词,它可以在定义函数时,用来引用父作用域中的变量;用法为 function($arg) use($outside_arg) {function_statement} 。其中$outside_arg 为父作用域中的变量,可以在function_statement使用。

这种用法用在回调函数“参数值数量确定”的函数中。 如usort需求$callback的参数值为两项,可是我们需要引入别的参数来影响排序怎么办呢?使用use()关键词就很方便地把一个新的变量引入$callback内部使用了。

array_map/array_filter/array_walk:

把这三个函数放在一块是因为这三个函数在执行逻辑上比较类似,类似于下面的代码:

$result = [];
foreach($vars as $key=>$val){
  $item = callback();
  $result[] = $item;
}
return $result;
array_walk($vars, $callback)

其callback应如下:

$callback = function(&$val, $key[, $arg]){  
  doSomething($val);
}

array_walk返回执行是否成功,是一个布尔值。对$value添加引用符号可以在函数内改变$value值,以达到改变$vars数组的效果。由于其$callback对参数数量要求为两项,array_walk不能传入strtolower/array_filter之类的$callback,若想实现类似功能,可以使用接下来要说的array_map()

array_walk_recursive($arr, $callback);

返回值和执行机制类似于array_walk;

其callback同array_walk,不同的是,如果$val是数组,函数会递归地向下处理$val;需要注意的是这样的话$val为数组的$key就会被忽略掉了。

array_filter($vars, $callback, $flag);

其$callback类似于:

$callback = function($var){
  return true or false;     
}

array_filter会过滤掉$callback执行时返回为false的项目,array_filter返回过滤完成后的数组。

第三个参数 $flag决定其callback形参$var的值,不过这个可能是PHP高版本的特性,我的PHP5.5.3不支持,大家可以自行测试。默认传入数组每项的value,当flag为ARRAY_FILTER_USE_KEY传入数组每项的key,ARRAY_FILTER_USE_BOTH传入键和值;

array_map($callback, &$var_as [,$var_bs...]);

其$callback类似于:

$callback = function($var_a[, $var_b...]){
  doSomething($var_a, $var_b);
}

返回$var_as经过callback处理后的数组(会改变原数组);如果有多个数组的时候将两个数组同样顺序的项目传入处理,执行次数为参数数组中项目最多的个数;

usort/array_reduce

把这两个函数放在一块,因为他们的执行机制都有些特殊。

usort(&$vars, $callback)

$callback应该如下:

callback = function($left, $right){
    $res = compare($left, $right);
    return $res;
}

usort返回执行成功与否,bool值。用户自定义方法 比较$left 和 $right,其中$left和$right是$vars中的任意两项;

$left > $right时返回 正整数, $left < $right时返回 负整数, $left = $right时返回0;

$vars中的元素会被取出会被由小到大升序排序。 想实现降序排列,将$callback的返回值反一下就行了。

array_reduce($vars ,$callable [, mixed $initial = NULL])

$callback应该如下:

$callback = function($initial, $var){
    $initial = calculate($initail, $var);
    return $initial;
}

初始值$initial默认为null,返回经过迭代后的initial;一定要将$initial返回,这样才能不停地改变$initial的值,实现迭代的效果。

这里顺便说一下map和reduce的不同:

map:将数组中的成员遍历处理,每次返回处理后的一个值,最后结果值为所有处理后值组成的多项数组;

reduce:遍历数组成员,每次使用数组成员结合初始值处理,并将初始值返回,即使用上一次执行的结果,配合下一次的输入继续产生结果,结果值为一项;

call_user_func/call_user_func_array

call_user_func[_array]($callback, $param)

$callback形如:

$callback = function($param){
    $result = statement(); 
    return $result;
}

返回值多种,具体看$callback。

可用此函数实现PHP的事件机制,其实并不高深,在判断条件达成,或程序执行到某一步后 call_user_func()就OK了。这个我在之前的博客中也有介绍到:搭建自己的PHP框架

总结

其实以上$callback不用单独定义并使用变量引用,使用上面说过的第四种函数定义方式,直接在函数内定义,使用‘完全'匿名函数就行了。 如:

usort($records, function mySortFunc($arg) use ($order){
  func_statement;
});

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
基于qmail的完整WEBMAIL解决方案安装详解
Oct 09 PHP
PHP CURL模拟GET及POST函数代码
Apr 25 PHP
慎用preg_replace危险的/e修饰符(一句话后门常用)
Jun 19 PHP
php获取$_POST同名参数数组的实现介绍
Jun 30 PHP
Codeigniter出现错误提示Error with CACHE directory的解决方案
Jun 12 PHP
php中json_encode UTF-8中文乱码的更好解决方法
Sep 28 PHP
phpcms手机内容页面添加上一篇和下一篇
Jun 05 PHP
php 获取文件行数的方法总结
Oct 11 PHP
PHP反射原理与用法深入分析
Sep 28 PHP
laravel-admin 后台表格筛选设置默认的查询日期方法
Oct 03 PHP
Thinkphp5.0 框架的请求方式与响应方式分析
Oct 14 PHP
PHP ob缓存以及ob函数原理实例解析
Nov 13 PHP
搭建自己的PHP MVC框架详解
Aug 16 #PHP
Laravel使用支付宝进行支付的示例代码
Aug 16 #PHP
laravel 中如何使用ajax和vue总结
Aug 16 #PHP
yii gridview实现时间段筛选功能
Aug 15 #PHP
PHP使用GD库制作验证码的方法(点击验证码或看不清会刷新验证码)
Aug 15 #PHP
Laravel学习教程之IOC容器的介绍与用例
Aug 15 #PHP
Laravel 5.4向IoC容器中添加自定义类的方法示例
Aug 15 #PHP
You might like
php2html php生成静态页函数
2008/12/08 PHP
Look And Say 序列php实现代码
2011/05/22 PHP
PHP的几个常用数字判断函数代码
2012/04/24 PHP
php调用dll的实例操作动画与代码分享
2012/08/14 PHP
php判断GIF图片是否为动画的方法
2020/09/04 PHP
thinkPHP5.0框架环境变量配置方法
2017/03/17 PHP
用JavaScript将从数据库中读取出来的日期型格式化为想要的类型。
2009/08/15 Javascript
jQuery1.3.2 升级到jQuery1.4.4需要修改的地方
2011/01/06 Javascript
用jQuery实现的智能隐藏、滑动效果的返回顶部代码
2014/03/18 Javascript
Js+Jq获取URL参数的集中方法示例代码
2014/05/20 Javascript
打造个性化的功能强大的Jquery虚拟键盘(VirtualKeyboard)
2014/10/11 Javascript
jQuery实现当前页面标签高亮显示的方法
2015/03/10 Javascript
关于获取DIV内部内容报错的原因分析及解决办法
2016/01/29 Javascript
懒加载实现的分页&amp;&amp;网站footer自适应
2016/12/21 Javascript
JS中定位 position 的使用实例代码
2017/08/06 Javascript
JS实现中文汉字按拼音排序的方法
2017/10/09 Javascript
jfinal与bootstrap的登出实战详解
2017/11/27 Javascript
vue2 v-model/v-text 中使用过滤器的方法示例
2019/05/09 Javascript
JS动态图片的实现方法完整示例
2020/01/13 Javascript
vue 封装面包屑组件教程
2020/11/16 Javascript
python验证码识别的实例详解
2016/09/09 Python
python学习必备知识汇总
2017/09/08 Python
详解python校验SQL脚本命名规则
2019/03/22 Python
python定时复制远程文件夹中所有文件
2019/04/30 Python
python写日志文件操作类与应用示例
2019/07/01 Python
对django后台admin下拉框进行过滤的实例
2019/07/26 Python
python禁用键鼠与提权代码实例
2019/08/16 Python
TensorFlow通过文件名/文件夹名获取标签,并加入队列的实现
2020/02/17 Python
Python如何生成xml文件
2020/06/04 Python
解析Tensorflow之MNIST的使用
2020/06/30 Python
铲车司机岗位职责
2014/03/15 职场文书
教师自我鉴定范文
2014/03/20 职场文书
好习惯伴我成长演讲稿
2014/05/21 职场文书
公务员中国梦演讲稿
2014/08/19 职场文书
基层党支部整改方案
2014/10/25 职场文书
javascript之Object.assign()的痛点分析
2022/03/03 Javascript