php的闭包(Closure)匿名函数详解


Posted in PHP onFebruary 22, 2015

php的闭包(Closure)也就是匿名函数,是PHP5.3引入的。

闭包的语法很简单,需要注意的关键字就只有use,use是连接闭包和外界变量。

$a = function() use($b) {}

简单例子如下:

function callback($fun) {

$fun();

}

$msg = "Hello, everyone";

$fun = function () use($msg) {

print "This is a closure use string value, msg is: $msg. <br />/n";

};

$msg = "Hello, everybody";

callback($fun);

结果是:This is a closure use string value, msg is: Hello, everyone. <br />/n

在PHP新开放的闭包语法中, 我们用use来使用闭包外部定义的变量的。这里我们使用了外部变量$msg,定义完之后,又对其值进行了改变,闭包被执行后输出的是原始值。以传值方式传递的基础类型参数,闭包use的值在闭包创建是就确定了。

小应用如下:

/** 

 * 一个利用闭包的计数器产生器 

 * 这里其实借鉴的是python中介绍闭包时的例子... 

 * 我们可以这样考虑: 

 *      1. counter函数每次调用, 创建一个局部变量$counter, 初始化为1. 

 *      2. 然后创建一个闭包, 闭包产生了对局部变量$counter的引用. 

 *      3. 函数counter返回创建的闭包, 并销毁局部变量, 但此时有闭包对$counter的引用,  

 *          它并不会被回收, 因此, 我们可以这样理解, 被函数counter返回的闭包, 携带了一个游离态的 

 *          变量. 

 *      4. 由于每次调用counter都会创建独立的$counter和闭包, 因此返回的闭包相互之间是独立的. 

 *      5. 执行被返回的闭包, 对其携带的游离态变量自增并返回, 得到的就是一个计数器. 

 * 结论: 此函数可以用来生成相互独立的计数器. 

 */  

function counter() {  

    $counter = 1;  

    return function() use(&$counter) {return $counter ++;};  

}  

$counter1 = counter();  

$counter2 = counter();  

echo "counter1: " . $counter1() . "<br />/n";  

echo "counter1: " . $counter1() . "<br />/n";  

echo "counter1: " . $counter1() . "<br />/n";  

echo "counter1: " . $counter1() . "<br />/n";  

echo "counter2: " . $counter2() . "<br />/n";  

echo "counter2: " . $counter2() . "<br />/n";  

echo "counter2: " . $counter2() . "<br />/n";  

echo "counter2: " . $counter2() . "<br />/n";  

?>

闭包的作用

1. 减少foreach的循环的代码
比如手册http://php.net/manual/en/functions.anonymous.php 中的例子Cart

<?php

// 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。

// 其中有一个方法用来计算购物车中所有商品的总价格。该方法使用了一个closure作为回调函数。

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";

// The result is 54.29

?>

这里如果我们改造getTotal函数必然要使用到foreach。

2. 减少函数的参数

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";

    };

}

如果是使用平时的方法,我们会把inner放到html函数参数中,这样不管是代码阅读还是使用都不如使用闭包。

3. 解除递归函数

<?php

$fib = function($n) use(&$fib) {

    if($n == 0 || $n == 1) return 1;

    return $fib($n - 1) + $fib($n - 2);

};

echo $fib(2) . "\n"; // 2

$lie = $fib;

$fib = function(){die('error');};//rewrite $fib variable 

echo $lie(5); // error   because $fib is referenced by closure

注意上题中的use使用了&,这里不使用&会出现错误fib(n-1)是找不到function的(前面没有定义fib的类型)

所以想使用闭包解除循环函数的时候就需要使用

<?php

$recursive = function () use (&$recursive){

// The function is now available as $recursive

}

这样的形式。

4. 延迟绑定

如果你需要延迟绑定use里面的变量,你就需要使用引用,否则在定义的时候就会做一份拷贝放到use中

<?php

$result = 0;

$one = function()

{

    var_dump($result);

};

$two = function() use ($result)

{

    var_dump($result);

};

$three = function() use (&$result)

{

    var_dump($result);

};

$result++;

$one();    // outputs NULL: $result is not in scope

$two();    // outputs int(0): $result was copied

$three();    // outputs int(1)

使用引用和不使用引用就代表了是调用时赋值,还是申明时候赋值

小伙伴们是否对PHP的匿名函数也就是闭包函数有了新的认识了呢,希望本文能给大家一些提示,希望大家能够喜欢。

PHP 相关文章推荐
防止MySQL注入或HTML表单滥用的PHP程序
Jan 21 PHP
对象失去焦点时自己动提交数据的实现代码
Nov 06 PHP
PHP Directory 函数的详解
Mar 07 PHP
PHP is_subclass_of函数的一个BUG和解决方法
Jun 01 PHP
php中使用GD库做验证码
Mar 31 PHP
Yii统计不同类型邮箱数量的方法
Oct 18 PHP
PHP之将POST数据转化为字符串的实现代码
Nov 03 PHP
php中static 静态变量和普通变量的区别
Dec 01 PHP
PHP获取文件扩展名的方法实例总结
Jun 10 PHP
php生成毫秒时间戳的实例讲解
Sep 22 PHP
用PHP的反射实现委托模式的讲解
Mar 22 PHP
Laravel 连接(Join)示例
Oct 16 PHP
PHP 实现代码复用的一个方法 traits新特性
Feb 22 #PHP
在Windows XP下安装Apache+MySQL+PHP环境
Feb 22 #PHP
PHP+APACHE实现网址伪静态
Feb 22 #PHP
php数组键名技巧小结
Feb 17 #PHP
php使用explode()函数将字符串拆分成数组的方法
Feb 17 #PHP
php使用unset()删除数组中某个单元(键)的方法
Feb 17 #PHP
php实现两个数组相加的方法
Feb 17 #PHP
You might like
给多个地址发邮件的类
2006/10/09 PHP
MySQL授权问题总结
2007/05/06 PHP
Windows Apache2.2.11及Php5.2.9-1的安装与配置方法
2009/06/08 PHP
php下把数组保存为文件格式的实例应用
2010/02/08 PHP
使用PHP函数scandir排除特定目录
2014/06/12 PHP
PHP引用的调用方法分析
2016/04/25 PHP
PHP基于PDO实现的SQLite操作类【包含增删改查及事务等操作】
2017/06/21 PHP
PHP实现的观察者模式实例
2017/06/21 PHP
(function(){})()的用法与优点
2007/03/11 Javascript
基于逻辑运算的简单权限系统(实现) JS 版
2007/03/24 Javascript
Ajax+Json 级联菜单实现代码
2009/10/27 Javascript
原生javascript实现拖动元素示例代码
2014/09/01 Javascript
微信小程序开发经验总结(推荐)
2017/01/11 Javascript
基于JavaScript实现带缩略图的轮播效果
2017/01/12 Javascript
Bootstrap选项卡学习笔记分享
2017/02/13 Javascript
使用svg实现动态时钟效果
2018/07/17 Javascript
初探Vue3.0 中的一大亮点Proxy的使用
2018/12/06 Javascript
微信小程序实现复选框效果
2018/12/28 Javascript
jQuery实现的中英文切换功能示例
2019/01/11 jQuery
JavaScript函数式编程(Functional Programming)声明式与命令式实例分析
2019/05/21 Javascript
vue实现移动端省市区选择
2019/09/27 Javascript
Python常见格式化字符串方法小结【百分号与format方法】
2016/09/18 Python
Python使用pickle模块储存对象操作示例
2018/08/15 Python
对Python Class之间函数的调用关系详解
2019/01/23 Python
python 批量添加的button 使用同一点击事件的方法
2019/07/17 Python
基于Python实现大文件分割和命名脚本过程解析
2019/09/29 Python
CSS3+font字体文件实现圆形半透明菜单具体步骤(图解)
2013/06/03 HTML / CSS
荷兰街头时尚之家:Funkie House
2019/03/18 全球购物
英国领先的隐形眼镜在线供应商:Lenstore.co.uk
2019/11/24 全球购物
工商管理本科毕业生求职信范文
2013/10/05 职场文书
家长评语和期望
2014/02/10 职场文书
党员干部2014全国两会学习心得体会
2014/03/10 职场文书
2015年大学班长个人工作总结
2015/04/24 职场文书
什么是执行力?9个故事告诉您:成功绝非偶然!
2019/07/05 职场文书
python如何进行基准测试
2021/04/26 Python
SQL语法CONSTRAINT约束操作详情
2022/01/18 MySQL