php 闭包函数 instanceof Closure
instanceof 作用:(1)判断一个对象是否是某个类的实例,(2)判断一个对象是否实现了某个接口。
PHP 闭包实现主要就是靠匿名函数
匿名函数,也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然也有其它应用的情况。
动态调用静态类的时候
<?php
class test
{
public static function getinfo()
{
var_dump(func_get_args());
}
}
call_user_func(array('test', 'getinfo'), 'hello world');
输出 hello world
PHP的闭包就是依赖于匿名函数
1. 声明一个匿名函数
$func = function(){
}
2. 使用匿名函数
$func = function($param){
echo $param;
}
$func ('调用匿名函数');
输出:调用匿名函数
将匿名函数在普通函数中当做参数传入,也可以被返回,这就是实现了一个简单的闭包
通俗的说: 子函数可以使用父函数中的局部变量,这种行为就叫做闭包
闭包的两个特点
- 作为一个函数变量的一个引用。当函数返回时,其处于激活状态
- 一个闭包就是当一个函数返回时,一个没有释放资源的栈区
其实上面两个点可以合成一个点,就是闭包函数返回时,该函数内部变量处于激活状态,函数所在栈区依然保留
function后面的括号相当于函数的用法,每次调用函数时传入数据一样,每次都需要传入,后面的use表示实例一次后不变,所有obj随时改变
闭包中的用法 匿名函数传参($obj)
function ($obj) use($param){}
use 的关键字使用(连接)了外部变量
如果没有&的符号,说明地址没有传进来,
function demo(){
$a = 20;
$b = 10;
#如果没有&的符号,说明地址没有传进来,
$one = function($str) use ($a, $b) {
echo $str."<br>";
echo $a."<br>";
$a++;
echo $b."<br>";
};
//调用了这个函数,$str输出hello world
$one('hello world');
echo "..........".$a."-------<br>";
}
demo();
输出的值
hello world
21
10
-----------------20--------------
如果用了& $oen = function($str) use (&$a, &$b) {
输出的值
hello world
21
10
-----------------21--------------
function demo(){
$a = 20;
$b = 10;
$one = function($str) use (&$a, &$b) {
echo $str."<br>";
echo $a."<br>";
$a++;
echo $b."<br>";
#不能return 可能会停止的
#return
};
return $one;
}
$var = demo();
$var("sdfsdf");
sdfsdf
20
10
$a 是demo局部变量 ,调用一次释放一次 ,要是使用了闭包,就能保护这个变量,只能在这一个内部去用 ,外面访问a和b访问不了。
function demo($fun){
#相当于调用test
echo $fun();
}
function test() {
return "################";
}
demo("test");
echo "\n";
echo test();
echo test(); 能不能直接调用呢
回调函数,直接把匿名函数当参数传进来
输出:
################
################
function demo($fun){
echo $fun();
}
#调用demo匿名函数参数传进来
demo(function(){
return "02222222222222222222222<br>";
});
demo(function(){
return "########################";
});
输出
02222222222222222222222
########################
function fullName($first_name ,$last_name,$callback){
return $callback($first_name ,$last_name);
}
#匿名函数当参数传递进去,以回调函数的方式处理业务逻辑
fullName('Lebron','James',function($first_name ,$last_name){
return $first_name . '' . $last_name;
});
echo $full_name
输出
Lebron James
闭包的三种方式
在函数里定义一个匿名函数,并且调用它
//闭包
function printStr($name) {//函数调用
$func = function( $str ) use ($name) {
echo $str.$name;
};
$func( 'some string' );
}
printStr('Clay');//函数调用
在函数中把匿名函数返回,并且调用它
//例二
//在函数中把匿名函数返回,并且调用它
function getPrintStrFunc() {
$func = function( $str ) {
echo $str;
};
return $func;
}
$printStrFunc = getPrintStrFunc();
$printStrFunc( 'some string' );
function enclosePerson($name)
{
//把匿名函数返回
return function ($doCommand) use ($name) {
var_dump($name);
var_dump($doCommand);
//把输出内容返回
return sprintf('%s, %s', $name, $doCommand);
};
}
//返回一个匿名函数
$clay = enclosePerson('Clay');
#var_dump($clay('get me sweet tea!'));exit;
#调用匿名函数
echo $clay('get me sweet tea!');
把匿名函数当做参数传递,并且调用它
function callFunc( $func ) {
$func( 'som11e string' );
}
$printStrFunc = function( $str ) {
echo $str;
};
callFunc( $printStrFunc );
//也可以直接将匿名函数进行传递。如果你了解js,这种写法可能会很熟悉
// callFunc( function( $str ) {
// echo $str;
// } );
循环里面写闭包这种方法不是很好用,相当于每次都实例
function后面的()为可变变量,use()里面的变量为实例一次后不改动的变量,循环里面写闭包这种方法不是很好用,相当于每次都实例,所以闭包的写法可以先定义一个方法在调用
$arr = [
'米' => ['咸粥','甜粥','米饭'],
'面' => ['面条','画卷','馒头'],
];
$parm = '';
//parm 外部的引用的变量 所以是空的
$bag = function($data) use ($parm){
// var_dump($data);exit;
// var_dump($parm);
$l = count($data);
return $data[rand(0,$l-1)];
};
$eat_arr =[];
foreach($arr as $key=> $value)
{
$each_arr [] = '吃'.$key.':'.$bag($value);
}
echo implode(',',$each_arr);
在这里插入代码片
$input = array(1, 2, 3, 4, 5, 6);
// 创建一个新的匿名函数然后赋值给一个变量
$filter_even = function($item) {
return ($item % 2) == 0;
};
// 内建函数 array_filter 接收数据和函数
$output = array_filter($input, $filter_even);
print_r($output);
// 函数不一定要被赋值到变量,下面这一也是可以的:
$output = array_filter($input, function($item) {
return ($item % 2) == 0;
});
print_r($output);
/**
- 创建一个匿名过滤函数,只接收大于$min 的数
*
- 在“大于n”的过滤器之外返回单个过滤器
*/
function criteria_greater_than($min)
{
return function($item) use ($min) {
return $item > $min;
};
}
$input = array(1, 2, 3, 4, 5, 6);
// 在input数组中使用已选的过滤函数来调用array_filter函数
$output = array_filter($input, criteria_greater_than(3));
print_r($output); // 大于3的元素
Closure
提到闭包就不得不想起匿名函数,也叫闭包函数(closures),貌似PHP闭包实现主要就是靠它。声明一个匿名函数是这样:
//匿名函数使用方式
$func = function() {
echo "This is";
}; //带结束符
//通过变量来调用
$func();
上面摘出来,代表闭包对象
function() {
echo "This is";
};
$func 如果是实例打印出来是个1
echo $func instanceof Closure
可以看到,匿名函数因为没有名字,如果要使用它,需要将其返回给一个变量。匿名函数也像普通函数一样可以声明参数,调用方法也相同:
$func = function( $param ) {
echo $param;
};
$func( 'some string' );
//输出:
//some string
顺便提一下,PHP在引入闭包之前,也有一个可以创建匿名函数的函数:create function,但是代码逻辑只能写成字符串,这样看起来很晦涩并且不好维护,所以很少有人用。
实现闭包
将匿名函数在普通函数中当做参数传入,也可以被返回。这就实现了一个简单的闭包。
下面请看例子
//例一
//在函数里定义一个匿名函数,并且调用它
function printStr() {
$func = function( $str ) {
echo $str;
};
$func( 'some string' );
}
printStr();
输出: some string
//例三
//把匿名函数当做参数传递,并且调用它
function callFunc( $func ) {
$func( 'some string' );
}
$printStrFunc = function( $str ) {
echo $str;
};
// print_r(callFunc( $printStrFunc ));
// //也可以直接将匿名函数进行传递。如果你了解js,这种写法可能会很熟悉
callFunc( function( $str ) {
echo $str;
} );
输出some string
连接闭包和外界变量的关键字:USE
闭包可以保存所在代码块上下文的一些变量和值。PHP在默认情况下,匿名函数不能调用所在代码块的上下文变量,而需要通过使用use关键字。
function getMoney() {
$rmb = 1;
$dollar = 6;
$func = function() use ( $rmb ) {
echo $rmb;
echo $dollar;
};
$func();
}
getMoney();
//输出:
//1
//报错,找不到dorllar变量
可以看到,dollar没有在use关键字中声明,在这个匿名函数里也就不能获取到它,所以开发中要注意这个问题。
有人可能会想到,是否可以在匿名函数中改变上下文的变量,但我发现是不可以的:
function getMoney() {
$rmb = 1;
$func = function() use ( $rmb ) {
echo $rmb;
//把$rmb的值加1
$rmb++;
};
$func();
echo $rmb;
}
getMoney();
//输出:
//1
//1
啊,原来use所引用的也只不过是变量的一个副本而已。但是我想要完全引用变量,而不是复制。
要达到这种效果,其实在变量前加一个 & 符号就可以了:
function getMoneyFunc() {
$rmb = 1;
$func = function() use ( &$rmb ) {
echo $rmb;
//把$rmb的值加1
$rmb++;
};
return $func;
}
$getMoney = getMoneyFunc();
$getMoney();
$getMoney();
$getMoney();
//输出:
//1
//2
//3
PHP之道–函数式编程(译)
Laravel路由中间件的实现原理
array_reduce与闭包嵌套
php闭包函数(Closure)