PHP闭包(Closure)使用详解


Posted in PHP onMay 02, 2013

不知不觉发现PHP已经出到了5.5版本,而自己一直在用PHP5.2,让我看起来像深山出来的小伙子一样,又土又落后。在我习惯在javascript中使用闭包之后,忽然间对PHP的闭包打起了兴趣。

于是乎在网上下了个WAMP集成开发环境,是PHP5.3版本的(PHP5.3开始引入了闭包的特性),不得不说WAMP安装使用真的很方便。简单配置了一下,开始动手。
 

匿名函数
提到闭包就不得不想起匿名函数,也叫闭包函数(closures),貌似PHP闭包实现主要就是靠它。声明一个匿名函数是这样:

$func = function() {}; //带结束符

可以看到,匿名函数因为没有名字,如果要使用它,需要将其返回给一个变量。匿名函数也像普通函数一样可以声明参数,调用方法也相同:
$func = function( $param ) {
    echo $param;
};
$func( 'some string' );
//输出:
//some string

顺便提一下,PHP在引入闭包之前,也有一个可以创建匿名函数的函数:create function,但是代码逻辑只能写成字符串,这样看起来很晦涩并且不好维护,所以很少有人用。
 

实现闭包
将匿名函数在普通函数中当做参数传入,也可以被返回。这就实现了一个简单的闭包。

下边有三个例子

//例一
//在函数里定义一个匿名函数,并且调用它
function printStr() {
    $func = function( $str ) {
        echo $str;
    };
    $func( 'some string' );
}
printStr();
 
//例二
//在函数中把匿名函数返回,并且调用它
function getPrintStrFunc() {
    $func = function( $str ) {
        echo $str;
    };
    return $func;
}
$printStrFunc = getPrintStrFunc();
$printStrFunc( 'some string' );
 

//例三
//把匿名函数当做参数传递,并且调用它
function callFunc( $func ) {
    $func( 'some string' );
}
$printStrFunc = function( $str ) {
    echo $str;
};
callFunc( $printStrFunc );
//也可以直接将匿名函数进行传递。如果你了解js,这种写法可能会很熟悉
callFunc( function( $str ) {
    echo $str;
} );

连接闭包和外界变量的关键字:USE
闭包可以保存所在代码块上下文的一些变量和值。PHP在默认情况下,匿名函数不能调用所在代码块的上下文变量,而需要通过使用use关键字。

换一个例子看看:

function getMoney() {
    $rmb = 1;
    $dollar = 6;
    $func = function() use ( $rmb ) {
        echo $rmb;
        echo $dollar;
    };
    $func();
}
getMoney();
//输出:
//1
//报错,找不到dorllar变量

可以看到,dollar没有在use关键字中声明,在这个匿名函数里也就不能获取到它,所以开发中要注意这个问题。
 

有人可能会想到,是否可以在匿名函数中改变上下文的变量,但我发现是不可以的:

function getMoney() {
    $rmb = 1;
    $func = function() use ( $rmb ) {
        echo $rmb;
        //把$rmb的值加1
        $rmb++;
    };
    $func();
    echo $rmb;
}
getMoney();
//输出:
//1
//1

啊,原来use所引用的也只不过是变量的一个副本而已。但是我想要完全引用变量,而不是复制。

要达到这种效果,其实在变量前加一个 & 符号就可以了:

function getMoney() {
    $rmb = 1;
    $func = function() use ( &$rmb ) {
        echo $rmb;
        //把$rmb的值加1
        $rmb++;
    };
    $func();
    echo $rmb;
}
getMoney();
//输出:
//1
//2

好,这样匿名函数就可以引用上下文的变量了。如果将匿名函数返回给外界,匿名函数会保存use所引用的变量,而外界则不能得到这些变量,这样形成‘闭包'这个概念可能会更清晰一些。

根据描述改变一下上面的例子:

function getMoneyFunc() {
    $rmb = 1;
    $func = function() use ( &$rmb ) {
        echo $rmb;
        //把$rmb的值加1
        $rmb++;
    };
    return $func;
}
$getMoney = getMoneyFunc();
$getMoney();
$getMoney();
$getMoney();
//输出:
//1
//2
//3

总结
PHP闭包的特性并没有太大惊喜,其实用CLASS就可以实现类似甚至强大得多的功能,更不能和js的闭包相提并论,只能期待PHP以后对闭包支持的改进。不过匿名函数还是挺有用的,比如在使用preg_replace_callback等之类的函数可以不用在外部声明回调函数了。
PHP 相关文章推荐
php生成SessionID和图片校验码的思路和实现代码
Mar 10 PHP
php 无限级数据JSON格式及JS解析
Jul 17 PHP
php 生成文字png图片的代码
Apr 17 PHP
php DOS攻击实现代码(附如何防范)
May 29 PHP
PHP判断是手机端还是PC端 PHP判断是否是微信浏览器
Mar 15 PHP
php连接mysql数据库
Mar 21 PHP
Laravel中如何增加自定义全局函数详解
May 09 PHP
PHP基于Closure类创建匿名函数的方法详解
Aug 17 PHP
wordpress自定义标签云与随机获取标签的方法详解
Mar 22 PHP
php策略模式简单示例分析【区别于工厂模式】
Sep 25 PHP
解决Laravel5.x的php artisan migrate数据库迁移创建操作报错SQLSTATE[42000]
Apr 06 PHP
Thinkphp5+Redis实现商品秒杀代码实例讲解
Dec 29 PHP
PHP5中Cookie与 Session使用详解
Apr 30 #PHP
PHP容易忘记的知识点分享
Apr 30 #PHP
基于curl数据采集之正则处理函数get_matches的使用
Apr 28 #PHP
基于curl数据采集之单页面并行采集函数get_htmls的使用
Apr 28 #PHP
基于curl数据采集之单页面采集函数get_html的使用
Apr 28 #PHP
基于php上传图片重命名的6种解决方法的详细介绍
Apr 28 #PHP
PHP基础学习之流程控制的实现分析
Apr 28 #PHP
You might like
discuz 首页四格:最新话题+最新回复+热门话题+精华文章插件
2007/08/19 PHP
基于PHP文件操作的详细诠释
2013/06/21 PHP
PHP使用mysql与mysqli连接Mysql数据库用法示例
2016/07/07 PHP
JQuery与JSon实现的无刷新分页代码
2011/09/13 Javascript
JavaScript高级程序设计(第3版)学习笔记 概述
2012/10/11 Javascript
JavaScript实现的一个计算数字步数的算法分享
2014/12/06 Javascript
javascript去除字符串左右两端的空格
2015/02/05 Javascript
JS函数的几种定义方式分析
2015/12/17 Javascript
jQuery拖动元素并对元素进行重新排序
2015/12/30 Javascript
深入学习js瀑布流布局
2016/10/14 Javascript
Bootstrap源码解读排版(1)
2016/12/23 Javascript
validationEngine 表单验证插件使用实例代码
2017/06/15 Javascript
JavaScript 中的 this 简单规则
2017/09/19 Javascript
浅谈angular4实际项目搭建总结
2017/12/01 Javascript
Vue常用的几个指令附完整案例
2018/11/06 Javascript
微信小程序通过一个json实现分享朋友圈图片
2019/09/03 Javascript
[48:31]完美世界DOTA2联赛PWL S3 DLG vs Phoenix 第二场 12.17
2020/12/19 DOTA
Python 利用切片从列表中取出一部分使用的方法
2019/02/01 Python
Python调用Windows API函数编写录音机和音乐播放器功能
2020/01/05 Python
python3使用Pillow、tesseract-ocr与pytesseract模块的图片识别的方法
2020/02/26 Python
重写django的model下的objects模型管理器方式
2020/05/15 Python
使用Keras加载含有自定义层或函数的模型操作
2020/06/10 Python
PyTorch: Softmax多分类实战操作
2020/07/07 Python
Python 捕获代码中所有异常的方法
2020/08/03 Python
python opencv图像处理(素描、怀旧、光照、流年、滤镜 原理及实现)
2020/12/10 Python
顶丰TOPPIK台湾官网:增发纤维假发,告别秃发困扰
2018/06/13 全球购物
G-Form护具官方网站:美国运动保护装备
2019/09/04 全球购物
教育学专业毕业生的自我评价
2013/11/21 职场文书
幼儿园运动会入场词
2014/02/10 职场文书
书法兴趣小组活动总结
2014/07/07 职场文书
教师批评与自我批评(群众路线)
2014/10/15 职场文书
python实现三阶魔方还原的示例代码
2021/04/28 Python
Python爬虫基础初探selenium
2021/05/31 Python
vue项目proxyTable配置和部署服务器
2022/04/14 Vue.js
pytorch实现加载保存查看checkpoint文件
2022/07/15 Python
Win11 22H2 2022怎么更新? 获得Win1122H22022版本升级技巧
2022/09/23 数码科技