首页 > 其他分享 >闭包Closure

闭包Closure

时间:2023-11-08 18:13:16浏览次数:24  
标签:闭包 Closure 函数 function echo 匿名

闭包

目的:实现函数的复用。

php会自动把闭包函数转换为内置的Closure的对象实例,依赖Closure对象实例给闭包函数增加了更多的能力。

闭包不能被实例(私有构造函数),也不能被继承(finally类)。可以通过反射来判断闭包实例是否能被实例,继承。

 

匿名函数

php5.3时引入,匿名函数,又称 Anonymous functions。

  • 声明一个匿名函数
$func = function($i){
    return 'i:'.$i;
};
echo $func(10);

 

实现闭包

实现方式:将匿名函数在普通函数中当作参数传递,或者 在函数中被返回。这就实现了简单的闭包。

连接闭包和外界变量的关键字: use

use引用外部变量,相当于clone副本,匿名函数内的操作不会改变该变量的上下文的值。

function numberAdd(){
    $i = 1;
    $func = function()use($i){
        $i++;
        echo 'i: '.$i.PHP_EOL;
    };
    return $func;
}

$num = numberAdd();
$num();//i: 2
$num();//i: 2
$num();//i: 2

可使用 & 来指向变量地址,来达到改变上下文值的目的。

将匿名函数返回给外界后,$i引用变量便被保存了,提升为全局变量。后面多次调用,传入的均为上一次保存后的值。

function numberAdd(){
    $i = 1;
    $func = function()use(&$i){
        $i++;
        echo 'i: '.$i.PHP_EOL;
    };
    return $func;
}

$num = numberAdd();
$num();//i: 2 
$num();//i: 3 ,这里多次调用的是匿名函数$func ,并非numberAdd(),故$i并未每次被重新初始值。
$num();//i: 4

 

绑定的概念

访问类下的匿名函数,即该匿名函数的访问范围不再是全局的,而是该类的访问范围。那么,就需要先 “将匿名函数绑定到类中” 。

PHP Closure类用于代表匿名函数的类,Closure类摘要如下:

Closure {
    __construct ( void ) //用于禁止实例化的构造函数
    public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ]) //复制一个闭包,绑定指定的$this对象和类作用域
    public Closure bindTo (object $newthis [, mixed $newscope = 'static' ]) //复制当前闭包对象,绑定指定的$this对象和类作用域。
}

参数说明:

$closure   需要绑定的匿名函数。

$newthis   需要绑定的匿名函数的对象,或者null创建未绑定的闭包。如果闭包中使用“$this”(使用$this只能调用非静态属性),则该参数不可以为null,只能是object对象。

$newscope 想要绑定给闭包的作用域。如果传入一个对象,则使用这个对象的类型名。类作用域用来决定在闭包中$this对象的private(私有)、protected(受保护的)的可见性。

                   默认参数”static“表示这个闭包和外部变量的作用域一样,不能访问类的私有和保护方法。

               如果闭包中访问的是private或protected属性,则需要该参数来提升权限。

 

 demo 函数复用实例

把函数挂在不同的类或对象上

class User{
    private $age = 30;
    private static $weight = 70;
    protected $height = 170;
    protected static $numLove = 6;
    public $name = 'KD';
    public static $six = 'man';
}

$funcName = function(){
    return $this->name;
};

$name = Closure::bind($funcName, new User());
echo $name().PHP_EOL; //echo KD

$funcHeight = function(){
    return $this->height;
};
$height = Closure::bind($funcHeight, new User(), new User());
echo $height().PHP_EOL; //echo 170

$funcNumLove = static function(){
    return self::$numLove; //ok
    // return User::$numLove; //ok ,IDE可能会出现错误提醒,但可以正常运行
};
$numberLove = Closure::bind($funcNumLove, null, new User());
echo $numberLove().PHP_EOL; //echo 6
$numberLove = Closure::bind($funcNumLove, null, 'User');
echo $numberLove().PHP_EOL; //echo 6

 闭包函数的实际应用

class Cart{
    //定义价格
    const PRICE_MILK = 2.5;
    const PRICE_COCO =  3;
    const PRICE_MEAT = 36;
    public $goods = array();
    
    function addCart($good, $number){
        $this->goods[$good] = $number;
    }

    /**
     * 根据税率计算总价
     * @param $rate 税率
     * @return float
     */
    function getTotal($rate){
        $total  = 0;
        //匿名函数,获取商品数量后,根据税率计算价格
        $func = function($number, $good) use ($rate, &$total){
            $price = constant(__CLASS__."::".strtoupper('price_'.$good)); //返回常量的值
            $total += $price * $number * (1+$rate);
        };
        //循环处理购物车中的商品,累计
        array_walk($this->goods, $func);
        return round($total);
    }
}

$cart = new Cart();
$cart->addCart('milk', 10);
$cart->addCart('coco', 1);
$cart->addCart('meat', 1);
$total = $cart->getTotal(0.2);
print_r($total); //echo 77

 

参考地址:PHP Closure(闭包)类详解

标签:闭包,Closure,函数,function,echo,匿名
From: https://www.cnblogs.com/wanghaokun/p/17816494.html

相关文章

  • 作用域和闭包
    一、作用域var可以重复声明,重复声明时实际是跳过声明处理,继续执行赋值操作。宽松模式下,a=2如果找不到a的声明,会在全局声明一个a;严格模式下严格模式禁止自动或隐式地创建全局变量。functionfoo(a){console.log(a+b);b=a;}foo(2);//ReferenceError:bisnot......
  • 前端歌谣-第贰拾陆课-闭包
    前言我是歌谣最好的种树是十年前其次是现在今天继续给大家带来的是闭包的讲解环境配置npminit-yyarnaddvite-D修改page.json配置端口{"name":"demo1","version":"1.0.0","description":"","main":"index.js",&......
  • JavaScript函数变量的生命周期,自执行函数、闭包、反转数组案例及冒泡排序案例
    一、变量的生命周期JavaScript变量的生命期从它们被声明的时间开始。局部变量会在函数运行以后被删除。全局变量会在页面关闭后被删除。二、自执行函数执行函数通常都是定义之后立即执行,以后都不再会调用,所以声明时可以省略函数名,因此自执行函数又叫匿名函数。通用的自执行......
  • 【闭包应用】JS:防抖、节流
    1、防抖:当进行连续操作时,只执行最后一次的操作。//防抖的概念是当进行连续操作时,只执行最后一次的操作。functiondebounce(fn,delayTime){lettimeout=null;returnfunction(){if(timeout){clearTimeout(timeout);......
  • 理解Golang的闭包
    闭包是指一个函数值(functionvalue),它可以引用其函数体之外的变量闭包代码示例funcmakeSuffix()func(strstring)string{ varsuffix=".jpg" returnfunc(strstring)string{ ifstrings.HasSuffix(str,suffix){ returnstr }else{ //引用函数体之外......
  • 自底向上的语法分析,闭包、GOTO函数
    自底向上的语法分析一、一个串ω归约(reduction)为文法开始符号的过程关键问题:1.何时进行规约,2.用哪个产生式规约句柄右边的串ω一定只包含终结符号。如果文法是无二义性的,那么文法的每个右句型都有且只有一个句柄二、LR(0)自动机Automaton项1.定义:产生式加上位于体中......
  • 经典闭包
     先看常见的问题internalclassProgram{staticvoidMain(string[]args){varactions=GetSomeAction();for(inti=0;i<actions.Count;i++)actions[i]();}staticList<Action>GetSomeAction(){......
  • JS加密/解密之闭包的运用
    深入探讨JavaScript闭包的演变与应用摘要:本文将深入探讨JavaScript闭包的概念、特性以及其在实际开发中的应用。我们将从闭包的起源开始,探讨它在JavaScript编程中的重要性,并通过实例展示闭包在不同场景下的灵活应用。引言JavaScript作为一种高度灵活的编程语言,一直以其独特的特性......
  • 从闭包谈到高阶函数
    1闭包的概念闭包是由一个函数以及与其相关的引用环境组合而成的实体。闭包可以在函数内部访问外部函数的变量,并且这些变量可以在外部函数执行结束后仍然保持其状态。听起来可能有点抽象,咱们来段代码:functionouterFunction(x){returnfunctioninnerFunction(y){ret......
  • 装饰器、闭包
    用到了老是忘记,还是记录一下吧,装饰器、闭包python的装饰器、闭包是进入Python高级语法的基础,使用装饰器之前,有以下条件:存在闭包存在需要被装饰的函数理解函数地址的概念理解函数的地址值众所周知,我们定义函数后,函数名加()可以调用函数,那么我们尝试调用一下函数名呢?def......