1. 程式人生 > >PHP中的閉包和匿名函數

PHP中的閉包和匿名函數

當前 call 內部 closure 參數 其它 來看 tput tro

PHP中的閉包和匿名函數

閉包是指在創建時封裝周圍狀態的函數。即使閉包所在的環境不存在了,閉包中封裝的狀態依然存在。

匿名函數就是沒有名稱的函數。匿名函數可以賦值給變量,還能像其他任何PHP對象那樣傳遞。不過匿名函數仍是函數,因此可以調用,還可以傳入參數。匿名函數特別適合作為函數或方法的回調。

註意:理論上講,閉包和匿名函數是不同的概念。不過,PHP將其視作相同的概念。所以,我們提到閉包時,指的也是匿名函數,反之亦然。

PHP閉包和匿名函數使用的句法與普通函數相同,但閉包和匿名函數其實是偽裝成函數的對象(Closure類的實例)

創建閉包

$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:

$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
    
    */

PHP中的閉包和匿名函數