我正在检查一些PHP 5.3.0
功能,并在网站上遇到了一些看起来颇有趣的代码: javascript
public function getTotal($tax) { $total = 0.00; $callback = /* This line here: */ 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); }
做为匿名函数的例子之一。 php
有人知道吗? 有文件吗? 并且看起来很邪恶,应该使用它吗? java
一个简单的答案。 程序员
function ($quantity) use ($tax, &$total) { .. };
数组
$tax
不会产生外部影响,除非它像对象同样是指针。 &$total
同样将变量做为指针传递。 这样,修改$total
的值确实具备外部效果,原始变量的值会更改。 正如@Mytskine 指出的那样 ,最好的深刻解释多是针对闭包的RFC 。 (为此投票给他。) 浏览器
这就是PHP表示闭包的方式 。 这根本不是邪恶的,实际上它是强大而有用的。 闭包
基本上,这意味着您容许匿名函数在其做用域以外“捕获”局部变量(在本例中$tax
和对$total
的引用)并保留其值(或在$total
的状况下,引用为( $total
自己)做为匿名函数自己内的状态。 异步
封口很漂亮! 它们解决了匿名函数带来的许多问题,并使真正优雅的代码成为可能(至少在咱们谈论php时)。 ide
javascript程序员一直在使用闭包,有时甚至不知道闭包,由于绑定变量未明肯定义-这就是php中“ use”的含义。 函数
有比以上示例更好的真实示例。 假设您必须按子值对多维数组进行排序,可是键会发生变化。
<?php function generateComparisonFunctionForKey($key) { return function ($left, $right) use ($key) { if ($left[$key] == $right[$key]) return 0; else return ($left[$key] < $right[$key]) ? -1 : 1; }; } $myArray = array( array('name' => 'Alex', 'age' => 70), array('name' => 'Enrico', 'age' => 25) ); $sortByName = generateComparisonFunctionForKey('name'); $sortByAge = generateComparisonFunctionForKey('age'); usort($myArray, $sortByName); usort($myArray, $sortByAge); ?>
警告:未经测试的代码(我没有在atm上安装php5.3),但它看起来应该像这样。
有一个缺点:若是您面对闭包的话,许多php开发人员可能会有些无奈。
为了进一步了解闭包的好处,我再举一个例子-此次使用javascript。 问题之一是范围和浏览器固有的异步性。 特别是关于window.setTimeout();
(或-interval)。 所以,您将一个函数传递给setTimeout,但实际上不能给出任何参数,由于提供参数会执行代码!
function getFunctionTextInASecond(value) { return function () { document.getElementsByName('body')[0].innerHTML = value; // "value" is the bound variable! } } var textToDisplay = prompt('text to show in a second', 'foo bar'); // this returns a function that sets the bodys innerHTML to the prompted value var myFunction = getFunctionTextInASecond(textToDisplay); window.setTimeout(myFunction, 1000);
myFunction返回带有某种预约义参数的函数!
老实说,自5.3起,我更喜欢php和匿名函数/闭包。 命名空间可能更重要, 但它们却不那么性感 。
Zupa在解释“使用”的闭包以及EarlyBinding和引用“已使用”变量之间的区别方面作得很是出色。
所以,我制做了一个带有早期绑定变量(=复制)的代码示例:
<?php $a = 1; $b = 2; $closureExampleEarlyBinding = function() use ($a, $b){ $a++; $b++; echo "Inside \$closureExampleEarlyBinding() \$a = ".$a."<br />"; echo "Inside \$closureExampleEarlyBinding() \$b = ".$b."<br />"; }; echo "Before executing \$closureExampleEarlyBinding() \$a = ".$a."<br />"; echo "Before executing \$closureExampleEarlyBinding() \$b = ".$b."<br />"; $closureExampleEarlyBinding(); echo "After executing \$closureExampleEarlyBinding() \$a = ".$a."<br />"; echo "After executing \$closureExampleEarlyBinding() \$b = ".$b."<br />"; /* this will output: Before executing $closureExampleEarlyBinding() $a = 1 Before executing $closureExampleEarlyBinding() $b = 2 Inside $closureExampleEarlyBinding() $a = 2 Inside $closureExampleEarlyBinding() $b = 3 After executing $closureExampleEarlyBinding() $a = 1 After executing $closureExampleEarlyBinding() $b = 2 */ ?>
引用变量的示例(注意变量前的“&”字符);
<?php $a = 1; $b = 2; $closureExampleReferencing = function() use (&$a, &$b){ $a++; $b++; echo "Inside \$closureExampleReferencing() \$a = ".$a."<br />"; echo "Inside \$closureExampleReferencing() \$b = ".$b."<br />"; }; echo "Before executing \$closureExampleReferencing() \$a = ".$a."<br />"; echo "Before executing \$closureExampleReferencing() \$b = ".$b."<br />"; $closureExampleReferencing(); echo "After executing \$closureExampleReferencing() \$a = ".$a."<br />"; echo "After executing \$closureExampleReferencing() \$b = ".$b."<br />"; /* this will output: Before executing $closureExampleReferencing() $a = 1 Before executing $closureExampleReferencing() $b = 2 Inside $closureExampleReferencing() $a = 2 Inside $closureExampleReferencing() $b = 3 After executing $closureExampleReferencing() $a = 2 After executing $closureExampleReferencing() $b = 3 */ ?>
function () use () {}
相似于PHP的闭包。
若是不use
,函数将没法访问父做用域变量
$s = "hello"; $f = function () { echo $s; }; $f(); // Notice: Undefined variable: s
$s = "hello"; $f = function () use ($s) { echo $s; }; $f(); // hello
use
变量的值来自定义函数时的值,而不是调用时的值
$s = "hello"; $f = function () use ($s) { echo $s; }; $s = "how are you?"; $f(); // hello
与&
一块儿use
变量按引用
$s = "hello"; $f = function () use (&$s) { echo $s; }; $s = "how are you?"; $f(); // how are you?