php中回调函数和匿名函数
回调函数、闭包在JS中并不陌生,JS使用它可以完成事件机制,进行许多复杂的操作。根据作用不同分为回调和匿名。
一、回调函数
就是将后续的操作交给用户来定义,比如js中的点击事件:
$('button').on('click', function(){
// ...
})
内核帮你注册了一个点击事件,点击完后要做什么则叫做回调,在php中也是一样的道理。
回调函数的参数也是由主程序定义好的并传递回来的,用户应该遵守。
定义
class swoole{
public function push($data, $func){
// 主要业务
....
$a = ...;
$b = ...;
$c = ...;
// 执行回调
call_user_func_array($func, [$a, $b, $c]);
}
}
调用
$swoole = new swoole();
$swoole->push($data, function($a, $b, $c) use($d) {
....
});
用户可以定义回调函数的业务逻辑,同样可以是use来引入外部参数使用。
二、匿名函数
匿名函数,顾名思义,是没有一个确定函数名的函数,PHP将匿名函数和闭包视作相同的概念(匿名函数在PHP中也叫作闭包函数)。它的用法,当然只能被当作变量来使用了。
定义
function test($name, $age, $callback){
return $callback($name, $age);
//或者,如果有参数
//return call_user_func_array($callback, [$name, $age]);
}
$a = 'rao';
$b = 123;
echo test($a, $b, function($x, $y){
return 'name:'.$x.', age:'.$y;
});
或者
$func = function($x, $y){
return 'name:'.$x.', age:'.$y;
};
echo test($a, $b, $func);
或者
function func($x, $y){
return 'name:'.$x.', age:'.$y;
}
echo test($a, $b, 'func');
通常在定义test的时候,闭包函数是不传参数的,需要用的参数都是由test函数来传,由闭包来使用,当然具体业务逻辑是由test和闭包来共同完成的,就比如 array_map($callback, $array),
$callback = function($val){
doSomething($val);
}
function array_map($callback, $array){
$result = [];
foreach($vars as $key=>$val){
$item = callback($val);
$result[] = $item;
}
return $result;
}
正常情况下,函数体内是无法调用外部的定义的变量的,需要通过参数传入到函数内部,作为闭包函数可以使用use关键字方便的将参数传递到函数体内部,多个参数通过逗号隔开
$n = 'rao';
echo test($n, function() use($n) {
return $n;
});
$n = 'rao';
$b = '123';
echo test($n, function() use($n, $b) {
return $n.'-'.$b;
});
需要注意的是$n,$b等变量需要在定义闭包函数之前定义,因为这个继承行为是在定义的时候产生的,而不是在调用时候产生的。也就是说传入闭包的值$n,$b的值在此刻就固定了,进入闭包体内后这两个变量的值就不会被外界干扰,内部的改变也不会影响外部的值,遵循函数体内局部变量的规则,例如:
$n = 'rao';
$b = '123';
$func = function() use($n, $b) {
return $n.'-'.$b;
};
$n = 'rao22';
$b = '12322';
echo test($n, $func); // rao-123
在匿名函数的use中如果使用引用传值,那么匿名函数中对参数值的改变会同样影响外部相应变量。
$n = 'rao';
echo test($n, function() use(&$n) {
$n = 'asd';
return $n;
});
echo "\n";
echo $n; // asd
那么是不是任何情况下,想通过匿名函数改变外部变量值都一定要通过引用方式向use传值呢?
显然不是,我们知道,当函数的参数为对象时,那么,不需要使用引用,在函数体内部改变了对象,那么这个对象就是被改变了。
所以,此处同样成立。那么,对于对象变量,加不加引用由什么区别呢,区别是:
1、加了引用后,对象变量在函数后定义也是可以的。
2、加了引用后,非对象变量在函数后定义不行。
3、不加引用,所有变量都需要在函数前面定义。
在类里面的匿名函数中$this依然表示该类的对象,直接使用即可,不需要use。
class C{
protected $_num = 0;
public function mkFunc(){
$func = function(){
echo $this->_num++, "\n";
};
return $func;
}
public function get(){
echo $this->_num,"\n";
}
}