其实闭包函数听起来很高大上,其实没什么,只是将函数作为参数传入函数或方法里边,再在函数或方法里边调用。我写了一个函数叫calculate($num1, $num2, $op),calculate函数的前面两个参数参数分别为两个数字,第三个参数$op是操作(如加减乘除),相信你已经想到了,如果如果calculate()的第三个参数我写成匿名函数会怎样,即
calculate($num1, $num2, function($n1, $n2) {
echo "$n1 + $n2 = " . $n1 + $n2;
});
那么我们就可以实现将$num1,$num2传入这个匿名函数中,结果就不用我说了。那么,问题来了,我们怎么传入参数呢?这就要用到一个比较有意思的函数了,叫func_get_args()
,获取传入该函数的参数,如果这还听不懂就去看手册,获取到的结果是一个数组,有趣的是,敲黑板了,他获取到的是你传入的参数,而不是对应的形参,也就是说你传多了几个,它也会获取到,利用这一点,我们就可以写成如下样子:
calculate($num1, $num2) {
$args = func_get_args();
$args[2]($num1, $num2);
}
这样的写法也跟php传入的参数多于形参也不会报错的特性有关,这样我们便实现了所谓的闭包的功能。
下面是我模仿laravel里边的chunk方法写的一个例子,里边还用到了递归,顺便可以学习一下递归 。如下:
<?php
/**
* Class FnCloseBag
* 时间:2018年02月18日16:24:40
* 目的:学习如何操作闭包函数
*/
class FnCloseBag
{
public function chunk()
{
//获取输入的参数,因为php就算定义没有要求输入参数,你输入参数也不会报错的,这就让你既可以输入参数也可以不输入参数
//不过你直接定义参数,默认为空也是可以的,一切都是为了逼格
$argv = func_get_args();
if (empty($argv)) {
echo 'hello?';
}
/****************要测试的话修改下数据库名,用户名,密码******************/
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', 'password');
/**
* @param $pdo 传入一个pdo对象,如果是框架直接调用框架里边的model就行了,我这里为了防止在递归里边多次创建对象
* @param $argv 将chunk方法获取到的参数传入,因为函数作用域的原因,所以要传进去
* @param int $next 游标的作用
* @return bool
*/
function re($pdo, $argv, $next = 0) {
//这里使用sprintf是为了方便书写sql语句,拼接容易出错
$sql = sprintf('select id, username from user limit %d, %d', $next, $argv[0]);
$resource = $pdo -> query($sql);
$data = $resource -> fetchAll(PDO::FETCH_ASSOC);
//所有数据取完后,就退出这个递归
if (!$data) {
return false;
}
//这里起到游标的作用,每次取完一次数据后,向后移动指定的条数
$next += $argv[0];
//这里将数据传入用户传进来的函数
$bool = $argv[1]($data);
//如果在用户传进来的函数中执行结果返回false,那么就终止递归
if ($bool === false) {
return false;
}
//调用自己,形成递归,运行前确保有退出条件
re($pdo, $argv, $next);
}
//开始递归调用函数
re($pdo, $argv);
}
}
//初始化对象
$fn = new FnCloseBag();
//调用方法
$fn -> chunk(2, function($data) {
var_dump($data);
//打印分割线是为了直观看出数据是分次取出的
echo '<br>----------------------<br>';
});