我正在檢查一些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?