我正在检查一些PHP 5.3.0功能,并在网站上遇到一些看起来很有趣的代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
作为匿名函数的一个例子.
有人知道吗?有文件吗?如果它被使用它看起来很邪恶?
zup*_*upa 456
一个更简单的答案.
function ($quantity) use ($tax, &$total) { .. };
$tax,在闭包内部进行修改没有外部效果,除非它是一个指针,就像对象一样.&$total.这样,修改$totalDOES 的值有外部效果,原始变量的值会发生变化.正如@Mytskine 指出的那样,关于闭包的RFC可能是最好的深入解释.(为此赞成他.)
And*_*are 346
这就是PHP表达闭包的方式.这根本不是邪恶的,事实上它非常强大和有用.
基本上这意味着您允许匿名函数在其范围之外"捕获"局部变量(在本例中$tax为引用$total)并保留它们的值(或者在$total引用$total自身的情况下)作为状态匿名函数本身.
Ste*_*ing 52
的function () use () {}就是关闭了PHP,你必须使用use包括父母的变量use.
$s = "hello";
$f = function () {
echo $s;
};
$f(); // Notice: Undefined variable: s
Run Code Online (Sandbox Code Playgroud)
ste*_*efs 51
封闭是美丽的!他们解决了许多匿名函数带来的问题,并且可以使代码变得非常优雅(至少只要我们谈论php).
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);
?>
Run Code Online (Sandbox Code Playgroud)
警告:未经测试的代码(我没有安装php5.3 atm),但它看起来应该是这样的.
有一个缺点:如果你用闭包来对付它们,很多php开发人员可能会有点无助.
为了更好地理解闭包的好处,我会给你另一个例子 - 这次是在javascript中.其中一个问题是范围和浏览器固有的异步性.特别是,如果涉及window.setTimeout();(或 - 间隔).所以,你将一个函数传递给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);
Run Code Online (Sandbox Code Playgroud)
myFunction返回一个带有一种预定义参数的函数!
说实话,自从5.3和匿名函数/闭包以来我更喜欢php.命名空间可能更重要,但它们的性感要差得多.
jor*_*imo 16
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
*/
?>
Run Code Online (Sandbox Code Playgroud)
引用变量的示例(注意变量前的'&'字符);
<?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
*/
?>
Run Code Online (Sandbox Code Playgroud)