php中的闭包

Reading time ~1 minute

在PHP中匿名函数(Anonymous functions),也叫闭包函数( closures ),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)的参数。 当然,也有其他应用的情况。

注:php闭包是PHP5.3版本之后才有的

php闭包函数也可以作为变量的值来使用。PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个变量的方式与普通变量赋值的语法是一样的,最后也要加上分号;

疑问

如果你在理解闭包函数的时候觉得比较费解,不如放一放,问自己一个问题: 面向对象编程语言对代码的复用主要采用继承来实现,那面向函数的代码复用能力通过什么来实现呢?

你可能第一时间想到的是 函数嵌套,就是通过独立子函数来组织代码。那类似PHP里面的array_walk()、array_udiff()这些函数怎么实现呢?是不是觉得,有了匿名函数,array_walk()、array_udiff()这两个函数才可能得到这么好的复用?

所以按照最基础的理解来总结,我个人认为 闭包函数 的主要目的是为了 函数复用 而设计的,如果某个语言不支持闭包函数,那再函数复用的能力上就会差一些,但是通过类的面向接口来编程,也可以很好的复用代码的,所以一切根源都是为了代码复用。

之所以闭包函数这么难理解,我觉得是网上太多帖子根据闭包函数的能力做了很多各种各样的例子,譬如怎么不用写for循环,怎么动态给类添加函数,这些的确是闭包函数的能力之一,但是比不是闭包函数设计的根源,所以会误导读者,让读者更不了解闭包函数。更好的理解方式应该是逆过来,先了解为什么需要闭包函数,闭包函数是怎么工作的,然后在来理解闭包函数有哪些应用场景。

总的来理解,我以为,PHP里面闭包函数是为了复用函数而设计的语言特性,类似JavaScript等具有面向函数的编程语言一样,可以在闭包函数里面访问指定域的变量,在PHP里使用use关键字来实现。

Closure

PHP具有面向函数的编程特性,但是也是面向对象编程语言,PHP 会自动把闭包函数转换成内置类 Closure 的对象实例,依赖Closure 的对象实例又给闭包函数添加了更多的能力。 例如Closure 的两个函数: Closure::bind —— 复制一个闭包,绑定指定的this对象和类作用域。Closure::bindTo —— 复制当前闭包对象,绑定指定的this对象和类作用域。

这两个函数的文字描述好让人费解,直白一点可以这样理解,通过这两个函数,可以指定闭包函数里 $this 变量的指向,和指明闭包函数的作用域。

具体底层怎么控制这个作用域就还没时间去看,不过知道作用域的概念就好。


闭包函数没有函数名称,直接在function()传入变量即可 使用时将定义的变量当作函数来处理:

<?php
$greet = function($name)
{
    printf("Hello %s\r\n", $name);
};

$greet('World');//Hello World
$greet('PHP');//Hello PHP
?>

直接通过定义为匿名函数的变量名称来调用

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
  return strtoupper($match[1]);
}, 'hello-world');
?>

闭包的语法很简单,需要注意的关键字就只有 use,闭包可以从父作用域中继承变量, 任何此类变量都应该用 use 语言结构传递进去,use 是连接闭包和外界变量。这些变量都必须在函数或类的头部声明。 从父作用域中继承变量与使用全局变量是不同的。全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而 闭包的父作用域是定义该闭包的函数(不一定是调用它的函数)。

<?php
$message = 'a';

// 没有 "use"
$example = function () {
    var_dump($message);
};
echo $example(); //Notice: Undefined variable: message in F:\bak\PASYS\test.php on line 6 NULL

// 继承 $message
$example = function () use ($message) {
    var_dump($message);
};
echo $example();//string(1) "a"

// 闭包声明后,$message重新赋值,再调用上面定义好的匿名函数
$message = 'b';
echo $example(); //string(1) "a"

// $message重新赋值
$message = 'c';

// 重新声明闭包 继承并引用 $message
$example = function () use (&$message) {
    var_dump($message);
    $message = 'ccc';
};
echo $example();//string(5) "c"
var_dump($message);//string(3) "ccc"

// $message重新赋值
$message = 'd';
echo $example();//string(1) "d"
var_dump($message);//string(3) "ccc"

// 闭包函数和其他函数一样可以定义参数
$example = function ($arg) use ($message) {
    var_dump($arg . ' ' . $message);
};
$example("e");//string(1) "e ccc"
?>

更多列子,请参考:

http://blog.csdn.net/wuxing26jiayou/article/details/51067190

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

Spring学习笔记:AOP

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OO...… Continue reading

Spring学习笔记:注解

Published on December 19, 2017

php队列 —— rabbitmq

Published on May 14, 2017