• 现代 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
  • 相关阅读:
    【3】jQuery学习——入门jQuery选择器之基本选择器
    对于转载引发的问题没见过这样强硬的论坛
    SQL2进制问题
    用SQL只获取日期的方法
    C#算法求2进制的问题
    ASP.NET Ajax In Action!读书笔记1
    Fckeditor配置
    MIME types list
    SQL case when then else end运用
    ASP.Net访问母版页(MasterPage)控件、属性、方法及母版页中调用内容页的方法
  • 原文地址:https://www.cnblogs.com/cshaptx4869/p/10775068.html
Copyright © 2020-2023  润新知