闭包匿名函数,还在傻傻搞不清楚吗?
闭包
还在正月里,首先祝大家新年快乐!本文是从PHP角度来看闭包与匿名函数。
闭包基础
闭包长啥样
以下是最常见的闭包形式,其他方法创建的闭包在此就不做说明了
$helloWorld = function() {
return 'hello world';
};
var_dump($helloWorld);
/*
返回结果如下:
object(Closure)#1 (0) {
}
*/
定义闭包
闭包 = 匿名函数 = 实例 = 对象。 类代码大概如下:
// 闭包类
class Closure{
// 禁止实例化
private __construct()
{
}
// 复制一个闭包,绑定指定的 $newThis 对象和类的作用域
public static function bind(Closure $closure, object $newThis, mixed $newscope = 'static') :Closure
{
// TO-DO
}
// 复制当前闭包对象, 绑定指定的 $newThis 对象和类的作用域
public function bindTo(object $newThis, mixed $newscope = 'static') :Closure
{
// TO-DO
}
// 魔术方法,无作用
public function __invoke()
{
// TO-DO
}
}
方法 | 说明 |
---|---|
__construct |
用于禁止实例化的构造方法 |
bind |
复制一个闭包,绑定指定的$this对象和类作用域 |
bindTo |
复制当前闭包,绑定指定的$this对象和类作用域 |
真实应用闭包
例如我们代码中需要将数组值转化int类型
$params = ['10', '20', '30', '40'];
$newArray = array_map(function($item) {
return intval($item);
}, $params);
var_dump($newArray);
/*
返回结果如下:
array(4) {
[0]=>
int(10)
[1]=>
int(20)
[2]=>
int(30)
[3]=>
int(40)
}
*/
闭包高级应用
Closure::bind
通俗点理解就是让我们的闭包代码块的作用域在某一类中或者对象中。使得闭包中的
$this->
self::
类名::
能指定到对象或者是类
代码块
/**
* Closure class a method
* 复制一个闭包,绑定指定的 $newThis对象和类的作用域
*
* @param Closure $closure
* @param object $newThis
* @param mixed $newscope
* @return \Closure
*/
public static function bind(Closure $closure, object $newThis, mixed $newscope = 'static') :Closure
{
// TO-DO
}
参数说明
PHP 手册 中有以下几句可加深我们理解:
创建并返回一个 匿名函数, 它与当前对象的函数体相同、绑定了同样变量,但可以绑定不同的对象,也可以绑定新的类作用域。
“绑定的对象”决定了函数体中的 $this 的取值,“类作用域”代表一个类型、决定在这个匿名函数中能够调用哪些 私有 和 保护 的方法。 也就是说,此时 $this 可以调用的方法,与 newscope 类的成员函数是相同的。
静态闭包不能有绑定的对象( newthis 参数的值应该设为 NULL)不过仍然可以用 bubdTo 方法来改变它们的类作用域。
参数 | 说明 |
---|---|
$closure |
表示闭包函数 |
$newThis |
闭包中 $this 所指的对象 |
$newscope |
我们闭包中需要操作属性等所属类的类型名 |
代码检验真理
class Order
{
private $orderId = '001';
private static $defaultMoney = '100';
public $num = 1;
}
$getOrderId = function() {
return $this->orderId;
};
$getNum = function() {
return $this->num;
};
$getDefaultMoney = static function() {
return Order::$defaultMoney;
};
1. Closure::bind($closure,null, 'Order')
给闭包绑定了Order类的作用域,但未绑定闭包$this对象 (Order::class == new Order() == 'Order')
$getDefaultMoney1 = Closure::bind($getDefaultMoney, null, Order::class);
// 输出:100
$getOrderId1 = Closure::bind($getOrderId, null, Order::class);
// 输出:PHP Fatal error: Uncaught Error: Using $this when not in object context
$getNum1 = Closure::bind($getNum, null, Order::class);
// 输出:PHP Fatal error: Uncaught Error: Using $this when not in object context
2. Closure::bind($closure,$object, 'Order')
给闭包绑定了Order类的作用域,将Order实例绑定闭包$this对象
$getDefaultMoney2 = Closure::bind($getDefaultMoney, new Order(), Order::class);
// 输出:PHP Warning: Cannot bind an instance to a static closure
$getOrderId2 = Closure::bind($getOrderId, new Order(), Order::class);
// 输出 string(3) "001"
$getNum2 = Closure::bind($getNum, new Order(), Order::class);
// 输出 int(1)
3. Closure::bind($closure,$object)
将Order实例对象作为$this对象绑定给闭包,保留闭包原有作用域
$getDefaultMoney3 = Closure::bind($getDefaultMoney, new Order());
// 输出 PHP Warning: Cannot bind an instance to a static closure
$getOrderId3 = Closure::bind($getOrderId, new Order());
// 输出 Fatal error: Uncaught Error: Cannot access private property Order::$orderId
$getNum3 = Closure::bind($getNum, new Order());
// 输出 int(1)
结论
$newThis | $newscope | 结果 |
---|---|---|
null |
Order::class |
可调用 Order 类作用域私有(受保护)的静态属性 |
new Order() |
Order::class |
可调用该对象的私有(受保护)的属性 |
new Order() |
默认值 | 可调用类作用域公共的属性 |
$closure->bindTo
与
Closure::bind
相同。一个是静态版,一个是非静态版。具体使用可以参考上面
$getOrderId1 = $getOrderId->bindTo(new Order(), Order::class);
小任务
利用闭包在不修改Order类的前提下增加
getOrderId
功能。最后实现的是如下两行代码调用方法。大家可以思考下
$order = new Order();
echo $order->getOrderId();
// 代码段
function getOrderId()
{
return $this->orderId;
}
闭包 == 匿名函数
感谢@Wi1dcard补充: 在 PHP 内,由于匿名函数是通过闭包类实现的( Anonymous functions are implemented using the Closure class
),因此多数人混淆了闭包技术和匿名函数;实际上,在其他语言内是完全不同的两个概念的。
参考:
http://php.net/manual/en/functions.anonymo...
https://stackoverflow.com/questions/491211...
闭包是一项「技术」或者说「功能」,能够捕获并存储当前当前上下文状态,以供后续使用。
匿名函数就只是一个「函数」,一个没有名字的函数而已。
在实际应用中,匿名函数通常伴随着使用闭包技术;但闭包并不一定只能用在匿名函数内。
相关链接
本作品采用《CC 协议》,转载必须注明作者和本文链接
高认可度评论:
搭个车补充一下:在 PHP 内,由于匿名函数是通过闭包类实现的(
Anonymous functions are implemented using the Closure class
),因此多数人混淆了闭包技术和匿名函数;实际上,在其他语言内是完全不同的两个概念的。参考:
闭包是一项「技术」或者说「功能」,能够捕获并存储当前当前上下文状态,以供后续使用。
匿名函数就只是一个「函数」,一个没有名字的函数而已。
在实际应用中,匿名函数通常伴随着使用闭包技术;但闭包并不一定只能用在匿名函数内。
仿照PHP手册写的,请大家看下
仿照PHP手册写的,请大家看下
真棒!
搭个车补充一下:在 PHP 内,由于匿名函数是通过闭包类实现的(
Anonymous functions are implemented using the Closure class
),因此多数人混淆了闭包技术和匿名函数;实际上,在其他语言内是完全不同的两个概念的。参考:
闭包是一项「技术」或者说「功能」,能够捕获并存储当前当前上下文状态,以供后续使用。
匿名函数就只是一个「函数」,一个没有名字的函数而已。
在实际应用中,匿名函数通常伴随着使用闭包技术;但闭包并不一定只能用在匿名函数内。
@Wi1dcard 多谢赐教。PHP手册中也写道了如此。我能否将你的见解补充到文章后面呢?
@悲剧不上演 当然可以,开源社区,大家互相学习~
nice
原来如此 高级!
mark
这么好的文章我居然一开始搜不到