php 閉包
文章轉載自:https://www.jb51.net/article/131408.htm
php閉包和匿名函式使用的句法與普通函式相同,但閉包和匿名函式其實是偽裝成函式的物件(Closure類的例項)。
閉包是指在建立時封裝周圍狀態的函式。即使閉包所在的環境不存在了,閉包中封裝的狀態依然存在。
匿名函式就是沒有名稱的函式。匿名函式可以賦值給變數,還能像其他任何php物件那樣傳遞。不過匿名函式仍是函式,因此可以呼叫,還可以傳入引數。匿名函式特別適合作為函式貨方法的回撥。
注意:理論上講,閉包和匿名函式是不同的概念。不過,PHP將其視作相同的概念。所以,我們提到閉包時,指的也是匿名函式,反之亦然。
PHP閉包和匿名函式使用的句法與普通函式相同,但閉包和匿名函式其實是 偽裝成函式的物件(Closure類的例項) 。
建立閉包
$closure = function($name){
return sprintf(''Hello %s",$name);
}
echo $closure("jerry");
var_dump($closure instanceof Closure);
以上程式碼建立了一個閉包物件,然後將其賦值給$closure
變數。閉包和普通的php函式很像,使用的句法相同,也接受引數,而且能返回值。
說明: 我們之所以能夠呼叫$closure
變數,是因為這個變數的值是一個閉包,而且閉包物件實現了__invoke()
__invoke()
方法。
使用閉包
我們通常把PHP閉包當做當做函式和方法的回撥使用。很多PHP函式都會用到回撥函式,例如 array_map()
和 preg_replace_callback()
.如下示例,我們將用 array_map()
處理陣列,將陣列每一項自增1:
$nubmers = array_map(function($number){
return $number++;
}, [1,2,3]);
var_dump($numbers);
附加狀態
PHP閉包不會像真正的javascrypt閉包那樣自動封裝應用的狀態,我們必須手動呼叫閉包物件的 bindTo()
use
關鍵字,把狀態附加到PHP閉包上。
使用 use 關鍵字
使用 use 關鍵字來附加閉包狀態更加常見,因此我們先來看這種方式。使用 use 關鍵字把變數附加閉包上時,附加的變數會記住附加時賦給它的值。
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類。因此,閉包可以訪問繫結閉包的物件中受保護和私有的成員變數。
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
*/