淺析PHP中的閉包和匿名函數
匿名函數就是沒有名稱的函數。匿名函數可以賦值給變量,還能像其他任何PHP對象那樣傳遞。不過匿名函數仍是函數,因此可以調用,還可以傳入參數。匿名函數特別適合作為函數或方法的回調。
註意:理論上講,閉包和匿名函數是不同的概念。不過,PHP將其視作相同的概念。所以,我們提到閉包時,指的也是匿名函數,反之亦然。
PHP閉包和匿名函數使用的句法與普通函數相同,但閉包和匿名函數其實是 偽裝成函數的對象(Closure類的實例) 。
創建閉包
?1 2 3 4 5 6 |
$closure = function ( $name ){
return sprintf( "Hello %s" , $name );
}
echo $closure ( "jerry" );
// 檢測$closure變量是否是一個閉包
var_dump( $closure instanceof Closure);
|
以上代碼創建了一個閉包對象,然後將其賦值給 $closure 變量。閉包和普通的PHP函數很像,使用的句法相同,也接收參數,而且能返回值。
說明:我們之所以能夠調用 $closure 變量,是因為這個變量的值是一個閉包,而且閉包對象實現了 __invoke() 魔術方法。只要變量名後有 () ,PHP就會查找並調用 __invoke()
使用閉包
我們通常把PHP閉包當做當做函數和方法的回調使用。很多PHP函數都會用到回調函數,例如 array_map()
和 preg_replace_callback()
.如下示例,我們將用 array_map() 處理數組,將數組每一項自增1:
1 2 3 4 |
$nubmers = array_map ( function ( $number ){
return $number ++;
}, [1,2,3]);
var_dump( $numbers );
|
附加狀態
PHP閉包不會像真正的javascrypt閉包那樣自動封裝應用的狀態,我們必須手動調用閉包對象的 bindTo() 方法或者使用 use 關鍵字,把狀態附加到PHP閉包上。
使用 use 關鍵字
使用 use 關鍵字來附加閉包狀態更加常見,因此我們先來看這種方式。使用 use 關鍵字把變量附加閉包上時,附加的變量會記住附加時賦給它的值。
?1 2 3 4 5 6 7 8 9 10 |
function Car ( $name ){
return function ( $statu ) use ( $name ){
return sprintf( "Car %s is %s" , $name , $statu );
}
}
// 將車名封裝在閉包中
$car = Car( "bmw" );
// 調用車的動作
// 輸出--> "bmw is running"
echo $car ( "running" );
|
註意:使用 use 關鍵字可以把多個參數傳入閉包,此時要像PHP函數或方法的參數一樣,使用逗號分隔多個參數。
使用 bindTo() 方法附加閉包的狀態
與其它PHP對象類似,每個閉包實例都可以使用 $this 關鍵字獲取閉包的內部狀態。閉包對象的默認狀態沒什麽用,不過有一個 __invoke() 魔術方法和 bindTo() 方法。
bindTo() 方法為閉包增加了一些有趣的潛力。我們可以使用這個方法把 Closure 對象的內部狀態綁定到其它對象上。
bindTo() 方法的第二個參數很重要,其作用是指定綁定閉包的那個對象所屬的PHP類。因此,閉包可以訪問綁定閉包的對象中受保護和私有的成員變量。
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
class TestClosure
{
private $name =[];
private $age ;
private $sex ;
public function addPerson( $name , $personCallback ){
// 將閉包對象綁定當前實例
$this ->name[ $name ] = $personCallback ->bindTo( $this , __CLASS__ );
}
public function display( $name ){
foreach ( $this ->name as $key => $callback ){
if ( $key == $name ){
// 執行閉包對象,將閉包狀態附加到類
$callback ();
}
}
echo "name : {$name}\n" ;
echo "age : {$this->age}\n" ;
echo "sex : {$this->sex}\n" ;
}
}
$person = new TestClosure();
$person ->addPerson( "jerry" , function (){
$this ->age = 19;
$this ->sex = "man" ;
});
$person ->display( "jerry" );
/** output
name : jerry
age : 19
sex : man
*/
|
淺析PHP中的閉包和匿名函數