写点什么

PHP 之闭包函数

用户头像
书旅
关注
发布于: 2020 年 08 月 14 日
PHP之闭包函数

在php语言中,闭包函数就是匿名函数

匿名函数就是没有名称的函数。匿名函数可以赋值给变量,还能像其他任何PHP对象那样传递。匿名函数仍是函数,因此可以调用,还可以传入参数。匿名函数特别适合作为函数或方法的回调。但,闭包和匿名函数其实是伪装成函数的对象(Closure类的实例)

例如:

<?php
$a = function () {
return "你调用了一个闭包函数";
};//注意闭包函数的末尾是有分号的哦!
echo $a();
//输出:你调用了一个闭包函数



这里就有个疑问了,前边我们说了闭包函数其实是伪装成函数的对象(不信的话,可以var_dump($a)看一下l类型),为什么可以直接$a()这样使用呢?

这个其实就是调用了对象里边的魔术方法__invoke(),关于PHP里边的魔术方法,自己也有过总结,如果对魔术方法的知识忘记了的可以看一下:

https://blog.csdn.net/self_realian/article/details/75095955



将闭包函数作为参数的情况

<?php
function b(\Closure $callback)
{
return $callback();
}
echo b($a);
//输出:你调用了一个闭包函数
//其实上边的写法就等同于
echo b(function () {
return '你调用了一个闭包函数';
});
//相对来说,这种写法使我们最常见到的



向闭包函数中传递参数的情况

<?php
$c = function ($param) {
return sprintf('Good %s', $param);
};
echo $c('Job');
//输出:Good Job



array_map()中的闭包函数

<?php
//看了上边是不是觉得很简单,那么我们看看它的应用
//其实很多的PHP函数都用到了闭包函数,比如array_map()函数
$arr = [1, 2, 3, 4, 5];
$res = array_map(function ($number) {
return $number * $number;
}, $arr);
print_r($res);//对数组中的每一项进行平方操作
/**
* 输出:
* Array
* (
* [0] => 1
* [1] => 4
* [2] => 9
* [3] => 16
* [4] => 25
* )
*/



闭包函数可以从父作用域中继承变量。这些变量可以使用use语言结构传递进去。因为PHP闭包函数不会像JavaScript的闭包那样自动封装应用的状态

<?php
//举个例子
$mes = 'hello';
$d = function () {
var_dump($mes);
};
echo $d();
//会报错:Notice: Undefined variable: mes
//现在我们利用use
$e = function () use ($mes) {
var_dump($mes);
};
echo $e();
//输出hello
//给闭包函数传递参数,且使用use的情况
$f = function ($arg) use ($mes) {
$str = $mes . ' ' . $arg;
var_dump($str);
};
echo $f('word');
//输出:hello word
//然后再看一个稍微复杂一些的情况
function A($book, $author)
{
return function ($money) use ($book, $author) {
return sprintf("This book names %s and Its author is %s,money %.2f", $book, $author, $money);
};
}
$book = A('PHP', 'shulv');
echo $book(66.66);
//输出:This book names PHP and Its author is shulv,money 66.66

在看laravel底层代码时,发现一个对象访问了私有成员,居然木有问题!!!what???上代码

<?php
//此方法是,通过执行此闭包,将自动加载映射规则注入到 loader 对象中
//方法中,$loader访问额属性均为私有属性
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInite1f2a23141b864cff8a83d4761dcae7c::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInite1f2a23141b864cff8a83d4761dcae7c::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInite1f2a23141b864cff8a83d4761dcae7c::$prefixesPsr0;
$loader->classMap = ComposerStaticInite1f2a23141b864cff8a83d4761dcae7c::$classMap;
}, null, ClassLoader::class);
}

为什么对象访问私有成员会没问题?其实这里是Closure::bind()方法在起作用,下边看一个栗子

<?php
Class B
{
private $name = '书旅';
}
$fun = function () {
return $this->name;
};
$res = Closure::bind($fun, new B(), 'B');
//Closure::bind()函数返回的是一个新的Cloure对象,失败的时候返回false
echo $res();
//输出:书旅
//为什么呢?bind方法的第一个参数是一个闭包函数,第二个参数为B类的对象,第三个参数代表作用域。我们看到的匿名函数里边的$this被指定到(或绑定)了B类实例的对象上了
Closure::bind($fun, new B());
//这个其实可以这么理解上边这行
$fun = function () {
$this = new B();
return $this->name;
};



其实就可以理解成$this就成了B类的对象了,然后去访问name属性。但$this是关键字,所以我们不能在代码中直接$this = new B();这样写,此处是为了方便理解

但是我们的name是私有,为什么对象可以访问呢?这里其实就是bind的第三个参数的作用。第三个参数一般为第二个参数这个对象的类名。第三个参数就是表明作用域为这个对象或类,这就使原来的私有属性name在此闭包函数中可当公有属性使用





发布于: 2020 年 08 月 14 日阅读数: 66
用户头像

书旅

关注

公众号:IT猿圈 2019.04.11 加入

还未添加个人简介

评论

发布
暂无评论
PHP之闭包函数