我正在檢查一些PHP 5.3.0功能,并在網站上遇到了一些看起來很有趣的代碼:
public function getTotal($tax)
{
$total = 0.00;
$callback =
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);
}
作為匿名函數的例子之一。
有人知道嗎? 有檔案嗎? 而且看起來很邪惡,應該使用它嗎?
#1樓
一個簡單的答案。
function ($quantity) use ($tax, &$total) { .. };
閉包是配置設定給變量的函數,是以您可以傳遞它
閉包是一個單獨的命名空間,通常,您不能通路此命名空間之外定義的變量。 使用關鍵字:
use允許您通路(使用)閉包内部的後續變量。
使用是早期綁定。 這意味着在定義閉包時将複制變量值。 是以,在閉包内部修改$tax不會産生外部影響,除非它像對象一樣是指針。
您可以像使用&$total一樣将變量作為指針傳遞。 這樣,修改$total的值确實具有外部效果,原始變量的值會更改。
在閉包内部定義的變量也不能從閉包外部通路。
閉合和功能具有相同的速度。 是的,您可以在所有腳本中使用它們。
正如@Mytskine 指出的那樣 ,最好的深入解釋可能是針對閉包的RFC 。 (為此投票給他。)
#2樓
這就是PHP表示閉包的方式 。 這根本不是邪惡的,實際上它是強大而有用的。
基本上,這意味着您允許匿名函數在其作用域之外“捕獲”局部變量(在本例中$tax和對$total的引用)并保留其值(或在$total的情況下,引用為( $total本身)作為匿名函數本身内的狀态。
#3樓
封口很漂亮! 它們解決了匿名函數帶來的許多問題,并使真正優雅的代碼成為可能(至少在我們談論php時)。
javascript程式員一直在使用閉包,有時甚至不知道閉包,因為綁定變量未明确定義-這就是php中“ use”的含義。
有比以上示例更好的真實示例。 假設您必須按子值對多元數組進行排序,但是鍵會發生變化。
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和匿名函數/閉包。 命名空間可能更重要, 但它們卻不那麼性感 。
#4樓
Zupa在解釋“使用”的閉包以及EarlyBinding和引用“已使用”變量之間的差別方面做得非常出色。
是以,我制作了一個帶有早期綁定變量(=複制)的代碼示例:
$a = 1;
$b = 2;
$closureExampleEarlyBinding = function() use ($a, $b){
$a++;
$b++;
echo "Inside \$closureExampleEarlyBinding() \$a = ".$a."
";
echo "Inside \$closureExampleEarlyBinding() \$b = ".$b."
";
};
echo "Before executing \$closureExampleEarlyBinding() \$a = ".$a."
";
echo "Before executing \$closureExampleEarlyBinding() \$b = ".$b."
";
$closureExampleEarlyBinding();
echo "After executing \$closureExampleEarlyBinding() \$a = ".$a."
";
echo "After executing \$closureExampleEarlyBinding() \$b = ".$b."
";
?>
引用變量的示例(注意變量前的“&”字元);
$a = 1;
$b = 2;
$closureExampleReferencing = function() use (&$a, &$b){
$a++;
$b++;
echo "Inside \$closureExampleReferencing() \$a = ".$a."
";
echo "Inside \$closureExampleReferencing() \$b = ".$b."
";
};
echo "Before executing \$closureExampleReferencing() \$a = ".$a."
";
echo "Before executing \$closureExampleReferencing() \$b = ".$b."
";
$closureExampleReferencing();
echo "After executing \$closureExampleReferencing() \$a = ".$a."
";
echo "After executing \$closureExampleReferencing() \$b = ".$b."
";
?>
#5樓
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?