PHP学习笔记: 闭包

闭包

闭包是一种语法结构, 它使你从内部函数访问外部函数作用域. 在js中,函数在每次创建时生成闭包. 闭包创建了一个环境, 这个环境包含了这个闭包创建时所能访问的所有局部变量

function makeFunc() {
    var name = "Jack";
    function displayName() {
        alert(name);
    }
    return displayName;
}

var myFunc = makeFunc();
myFunc();

如, 上面例子中, makeFunc() 执行完毕后,name仍然可以在myFunc中被访问

js中的闭包使js实现类似面向对象编程, 因为它允许将函数与其所操作的某些数据(环境)关联起来, 类似于对象允许我们将某些数据(对象的属性)与一个或者多个方法相关联

在这个例子中,我们在函数makeFunc中又定义了函数displayName,并且,内部函数displayName可以引用外部函数makeFunc的参数和局部变量,当nameFunc返回函数displayName时,相关参数和变量都保存在返回的函数中,这就是闭包(Closure)

PHP中的闭包

(1) 实现闭包

首先,闭包在PHP中的实现需要借助匿名函数.  顾名思义,匿名函数没有名字,需要将它返回到一个变量中

$func = function(){

};//有结束符

匿名函数也可以声明参数, 像普通函数一样

$func = function($a){
    echo $a;
};
$func('abc'); // 输出: abc

实现闭包: 将匿名函数作为参数传入普通函数, 就实现了一个简单的闭包

$echoStr = function($str){
    echo $str;
};
function callFunc($func){
    $func('abc');
}
callFunc($echoStr);

也可以直接传递匿名参数, 类似js的写法

callFunc(function($str){
    echo $str;
});

此外, 还有在函数内部定义匿名函数并调用的例子

function printStr(){
    $funcName = function($a){
        echo $a;
    };
    $funcName('abc');
}
printStr();
// 或者, 将匿名函数返回后,再调用
function printStrFunc(){
    $funcName = function($a){
        echo $a;
    };
    return $funcName;
}
$printStr = printStrFunc();
$printStr('abc');
关键字use: 实现闭包对外界变量的引用. PHP默认情况下, 匿名函数不能调用外界变量, 故需要通过use关键字实现对上下文变量的调用
function goAhead(){
    $step = 1;
    $func = function() use($step) {
        echo $step;
        $step ++;
    };
    $func();
    echo $step;
}
goAhead();
//输出
//1
//1

上面的情况下调用的是变量的副本, 匿名函数无法改变上下文变量. 如果需要完全引用变量,在变量前加一个 & 符号就可以了

function goAhead2(){
    $step = 1;
    $func = function() use( &$step ) {
        echo $step;
        $step ++;
    };
    $func();
    echo $step;
}
goAhead2();
//输出
//1
//2

最后, 如果将匿名函数return返回, 匿名函数将会保存use引用的变量,而外界不能得到这些变量,这样的"闭包"的概念会更清晰

function goAhead3(){
    $step = 1;
    $func = function() use( &$step ) {
        echo $step;
        $step ++;
    };
    return $func;
}
$getStep = goAhead3();
$getStep();
$getStep();
$getStep();
//输出:
//1
//2
//3

(2)闭包的作用

PHP闭包远不及JavaScript闭包强大,而且用class就可代替. PHP闭包的作用有以下几点:

一,减少循环, PHP手册中购物车的例子, getTotal方法用闭包代替了循环

class Cart
{
    const PRICE_BUTTER  = 1.00;
    const PRICE_MILK    = 3.00;
    const PRICE_EGGS    = 6.95;

    protected   $products = array();

    public function add($product, $quantity)
    {
        $this->products[$product] = $quantity;
    }

    public function getQuantity($product)
    {
        return isset($this->products[$product]) ? $this->products[$product] :
            FALSE;
    }

    public function getTotal($tax)
    {
        $total = 0.00;

        $callback =
            function ($quantity, $product) use ($tax, &$total)
            {
                $pricePerItem = constant(__CLASS__ . "::PRICE_" .
                    strtoupper($product));
                $total += ($pricePerItem * $quantity) * ($tax + 1.0);
            };

        array_walk($this->products, $callback);
        return round($total, 2);
    }
}

$my_cart = new Cart;

// 往购物车里添加条目
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);

// 打出出总价格,其中有 5% 的销售税.
print $my_cart->getTotal(0.05) . "\n";
// 最后结果是 54.29

二, 减少参数传递, 使代码易读

function html ($code ,$id="",$class=""){

    if ($id !=="") $id =" id = \"$id\"" ;
    $class = ($class !== "") ? " class =\"$class\">" : ">";
    $open = "<$code$id$class";
    $close ="</$code>";

    return function ($inner="") use ($open,$close){
        return "$open$inner$close";
    };
}

$getHtml = html('h2','hid','hclass');
$html = $getHtml('contents');
echo $html; //输出 <h2 id="hid" class="hclass">contents</h2>

不使用闭包的话, inner参数可能也会在html函数中传入, 代码的阅读和使用不如使用闭包更清晰

三, 解除递归函数, use后的循环函数前需要加 & 符号

$fib =function($n)use(&$fib) {
    if($n == 0 || $n == 1) return 1;
    return $fib($n - 1) + $fib($n - 2);
};

echo $fib(0) . "\n";// 1
echo $fib(1) . "\n";// 1
echo $fib(2) . "\n";// 2
echo $fib(3) . "\n";// 3
echo $fib(4) . "\n";// 5
echo $fib(5) . "\n";// 8

四, 延迟绑定

$num = 0;
$func1 = function(){
    echo $num;
};
$func2 = function()use($num){
    echo $num;
};
$func3 = function()use(&$num){
    echo $num;
};
$num ++;

$func1();// null, 匿名函数无法调用外界变量
$func2();// 0, 传递的是$num的副本
$func3();// 1, 实现了调用时赋值,延时绑定变量

参考链接:

https://www.cnblogs.com/melonblog/archive/2013/05/01/3052611.html

https://www.cnblogs.com/yjf512/archive/2012/10/29/2744702.html

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值