现代 PHP 新特性 —— 闭包

一、概述

https://www.php.net/manual/zh/class.closure.php

闭包是指在创建时封装周围状态的函数,即使闭包所在的环境的不存在了,闭包中封装的状态依然存在。
闭包对象实现了__invoke()魔术方法,只要变量名后有(),PHP就会查找并调用__invoke方法。

1、闭包可以赋值给变量
2、闭包可以作为参数(回调函数)传递给函数
3、闭包可以作为函数的返回值
4、定义一个闭包函数,即产生了一个闭包类(Closure)的对象

Closure {
        /* Methods */
        private __construct ( void )

        /**
         * Closure::bindTo的静态版本
         */
        public static bind ( Closure $closure , object $newthis [, mixed $newscope = "static" ] ) : Closure
        
        /**
         * 复制当前闭包对象,绑定指定的$this对象和类作用域。
         */
        public bindTo ( object $newthis [, mixed $newscope = "static" ] ) : Closure

        /**
         * 绑定闭包对象到$newthis,并使用参数$parameters进行调用
         */
        public call ( object $newthis [, mixed $... ] ) : mixed

        /**
         * 将一个callable对象转换成一个闭包对象
         */
        public static fromCallable ( callable $callable ) : Closure
    }

方法说明:

Closure::bind: 复制一个闭包,绑定指定的 $this 对象和类作用域。是 Closure::bindTo() 的静态版本。
Closure::bindTo: 复制当前闭包对象,绑定指定的 $this 对象和类作用域。

call()fromCallable()是从PHP 7.0以后新增的。

bind参数和返回值说明:
closure:表示需要绑定的闭包对象。
newthis:表示需要绑定到闭包对象的对象,或者 NULL 创建未绑定的闭包。
newscope:表示想要绑定给闭包的类作用域,可以传入类名或类的示例,默认值是'static', 表示不改变。类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性
该方法成功时返回一个新的 Closure 对象,失败时返回 FALSE。

bindTo参数和返回值说明:
newthis:表示需要绑定到闭包对象的对象,或者 NULL 创建未绑定的闭包。
newscope:表示想要绑定给闭包的类作用域,可以传入类名或类的示例,默认值是'static', 表示不改变。

使用:

 Closure类的bindTo()bind()方法提供了将一个闭包绑定到一个类对象的功能

<?php

class Animal {  
    private static $cat = "cat";  
    private $dog = "dog";  
    public $pig = "pig";  

    public function say(string $param)
    {
        return 'hello '. $param;
    }
}  

/*  
 * 获取Animal类静态私有成员属性 
 */  
$cat = static function() {  
    return Animal::$cat;  
};  

/*  
 * 获取Animal实例私有成员属性 
 */  
$dog = function() {  
    return $this->dog;  
};  

/*  
 * 获取Animal实例公有成员属性 
 */  
$pig = function() {  
    return $this->say($this->pig);  
};  

// 给闭包绑定了Animal实例的作用域,但未给闭包绑定$this对象,因此不能使用$this对象  
$bindCat = Closure::bind($cat, null, new Animal());
// 给闭包绑定了Animal类的作用域,同时将Animal实例对象作为$this对象绑定给闭包,因此可以访问非公有的属性和方法  
$bindDog = Closure::bind($dog, new Animal(), 'Animal');
// 将Animal实例对象作为$this对象绑定给闭包,保留闭包原有作用域,因此只能调用公有的属性和方法  
$bindPig = Closure::bind($pig, new Animal());
// 根据绑定规则,允许闭包通过作用域限定操作符获取Animal类静态私有成员属性,若没有作用域,则只能访问公有的  
echo $bindCat(),'<br>'; // cat
// 根据绑定规则,允许闭包通过绑定的$this对象(Animal实例对象)获取Animal实例所有的成员属性和方法
echo $bindDog(),'<br>'; // dog
// 根据绑定规则,允许闭包通过绑定的$this对象获取Animal实例公有成员属性和方法
echo $bindPig(),'<br>'; // hello pig

// bindTo与bind类似,bind是bindTo的静态版本,这里只举一个,其他类比就可以
$bindCat = $cat->bindTo(null, 'Animal');
echo $bindCat(); // cat

 官方实例

<?php

class A {
    function __construct($val) {
        $this->val = $val;
    }
    function getClosure() {
        //returns closure bound to this object and scope
        return function() { return $this->val; };
    }
}

$ob1 = new A(1);
$ob2 = new A(2);

$cl = $ob1->getClosure();
echo $cl(), "
"; // 1
$cl = $cl->bindTo($ob2);
echo $cl(), "
"; // 2

 call 绑定闭包对象到$newthis,并使用参数$parameters进行调用

<?php
class Value {
    protected $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }
}

$three = new Value(3);
$four = new Value(4);

$closure = function ($delta) { var_dump($this->getValue() + $delta); };
$closure->call($three, 4); // 7
$closure->call($four, 4); // 8

 二、综合实例

<?php

class A
{
    public $a;

    public function __construct($a)
    {
        $this->a = $a;
    }

    public function getValue()
    {
        return $this->a;
    }
}

function say($world = 'hello world!')
{
    return $world;
}

function say2()
{
    return $this->getValue();
}

$say3 = function () {
    return $this->getValue();
};

$obj = new A('aaa');

// 转为闭包对象
$say1 = Closure::fromCallable('say');
$func1 = $say1->bindTo($obj);
echo $func1(), '<br>'; // hello world!

// 将函数转为闭包
$say2 = Closure::fromCallable('say2');
$func2 = $say2->bindTo($obj);
echo $func2(), '<br>'; // aaa

// 绑定闭包对象到$obj,并进行调用
echo $say3->call($obj),'<br>'; // aaa

// 使用bind的静态版本
$func3 = Closure::bind($say3, $obj);
echo $func3(); // aaa
原文地址:https://www.cnblogs.com/cshaptx4869/p/10775068.html