首页 » PHP » 【转】PHP 闭包

【转】PHP 闭包

 

本文转载自《Modern PHP(中文版)》第二章 闭包

闭包和匿名函数在 PHP 5.3.0 中引入,这是我最喜欢的两个 PHP 特性,使用的也最多。这两个特性听起来很吓人(至少我第一次听说时有这种感觉),其实很容易理解。这两个特性非常有用,每个 PHP 开发者都应该掌握。

闭包是指在创建时封装周围状态的函数。即便闭包所在的环境不存在了,闭包中封装的状态依然存在。这个概念很难理解,不过一旦掌握,将会对你的生活带来巨大变化。

匿名函数其实就是没有名称的函数。匿名函数可以赋值给变量,还能像其他任何 PHP 对象那样传递。不过匿名函数仍是函数,因此可以调用,还可以传入参数。匿名函数特别适合作为函数或方法的回调。

注意:理论上讲,闭包和匿名函数是不同的概念。不过,PHP 将其视作相同的概念。所以,我提到闭包时,指的也是匿名函数,反之亦然。

PHP 闭包和匿名函数使用的句法与普通函数相同,不过别被这一点迷惑了,闭包和匿名函数其实是伪装成函数的对象。如果审查 PHP 闭包或匿名函数,会发现它们是 Closure 类的实例。闭包和字符串或整数一样,也是一等值类型。

创建闭包

既然我们知道闭包和函数很像,那么你应该不会奇怪,我们可以像示例 2-19 这样创建 PHP 闭包

示例 2-19:创建简单的闭包

就这么简单。示例 2-19 创建了一个闭包对象,然后将其赋值给 $closure 变量。闭包和普通的 PHP 函数很像:使用的句法相同,也能接受参数,而且能返回值。不过匿名函数没有名称。

建议:我们之所以能调用 $closure 变量,是因为这个变量的值是一个闭包,而且闭包对象实现了 __invoke() 魔术方法。只要变量名后有 (),PHP 就会查找并调用 __invoke() 方法。

我通常把 PHP 闭包当作函数和方法的回调使用。很多 PHP 函数都会用到回调函数,例如 array_map() 和 preg_replace_callback()。这是使用 PHP 匿名函数的绝佳时机!记住,闭包和其他值一样,可以作为参数传入其他 PHP 函数。在示例 2-20 中,我把一个闭包对象当作回调参数,传给 array_map() 函数。

示例 2-20:在 array_map() 函数中使用闭包

好吧,这并不惊艳。可是要知道,在闭包出现之前,PHP 开发者别无选择,只能单独创建具名函数,然后使用名称引用那个函数。这么做,代码执行得稍微慢一点,而且把回调的实现和使用场所隔离开了。传统的 PHP 开发者会使用类似下面的代码:

这样的代码虽然可用,但是没有示例 2-20 简洁。如果只需使用一次回调,没必要单独定义具名函数 incteamentNumber()。把闭包当成回调使用,写出的代码更简洁,更清晰。

附加状态

前面我演示了如何把匿名函数当成回调使用,下面探讨如何为 PHP 闭包附加并封装状态。JavaScript 开发者可能对 PHP 的闭包感到奇怪,因为 PHP 闭包不会像真正的 JavaScript 闭包那样自动封装应用的状态。在 PHP 中,必须手动调用闭包对象的 bindTo() 方法或者使用 use 关键字,把状态附加到 PHP 闭包上。

使用 use 关键字附加闭包状态常见的多,因此我们先看这种方式(如示例 2-21 所示)。使用 use 关键字把变量附加到闭包上时,附加的变量会记住附加时赋给他的值。

示例 2-21:使用 use 关键字附加闭包的状态。

在示例 2-21 中,具名函数 enclosePerson() 有个名为 $name 的参数,这个函数返回一个闭包对象,而且这个闭包封装了 $name 参数,即便返回的闭包对象跳出了 enclosePersen() 函数的作用域,它也会记住 $name 参数的值,因为 $name 变量仍在闭包中。

建议:使用 use 关键字可以把多个参数传入闭包中,此时要像 PHP 函数或方法的参数一样,使用都好分隔多个参数。

别忘了,PHP 闭包是对象。与任何其他 PHP 对象类似,每个闭包实例都可以使用 $this 关键字获取闭包的内部状态。闭包对象的默认状态没什么用,不过有一个 __invoke() 魔术方法和 bindTo() 方法,仅此而已。

但是,bintTo() 方法为闭包增加了一些有趣的潜力。我们可以使用这个方法把 Closure 对象的内部状态绑定到其他对象上。bindTo() 方法的第二个参数很重要,其作用是指定绑定闭包的那个对象所属的 PHP 类,因此,闭包可以访问绑定闭包的对象中受保护和私有的成员变量。

你会发现,PHP 框架经常使用 bindTo() 方法把路由 URL 映射到匿名回调函数上。框架会把匿名函数绑定到应用对象上,这么做可以在这个匿名函数中使用 $this 关键字引用重要的应用对象,如示例 2-22 所示。

示例 2-22:使用 bindTo() 方法附加闭包状态

我们要特别注意 addRoute() 方法。这个方法的参数分别是一个路由路径(例如 /users/josh)和一个路由回调。dispatch() 方法的参数是当前 HTTP 请求的路径,它会调用匹配的路由回调。第 9 行是重点所在,我们把路由回调绑定到了当前的 App 实例上。这么做能在回调函数中处理 App 实例的状态。:

 

原文链接:【转】PHP 闭包,转载请注明来源!

0