首頁  >  文章  >  後端開發  >  PHP的匿名函數和閉包是什麼?如何創建?

PHP的匿名函數和閉包是什麼?如何創建?

PHPz
PHPz轉載
2016-07-29 08:33:421980瀏覽


這篇文章帶給大家的內容是介紹PHP的匿名函數和閉包是什麼?如何建立匿名函數和閉包?有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

概述

閉包和匿名函數在PHP 5.3.0中引入,這兩個特性非常有用,每個PHP開發者都應該掌握。

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

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

建立匿名函數

建立匿名函數很簡單:

//将匿名函数赋给一个变量,通过变量名+()的形式来调用
$greet = function () {
    return "Hello World";
};

echo $greet();

結果列印:

Hello World

結果列印:
$greet__invoke()__invoke結果列印:

array_mappreg_replace_callback結果打印>

匿名函數和普通的PHP函數很像:常用的句法相同,也接受參數,而且能回傳值。不過閉包沒有函數名。
$numberPlusOne = array_map(function ($number) {
    return $number += 1;
}, [1, 2, 3]);

print_r($numberPlusOne);

註:我們之所以能呼叫

變量,是因為這個變量的值是一個閉包,而且閉包對象實現了
function incrementNumber ($number) {
    return $number += 1;
}

$numberPlusOne = array_map(‘incrementNumber’,  [1, 2, 3]);
print_r($numberPlusOne);
魔術方法,只要變量名後有(),PHP就會尋找並呼叫

方法。

我們通常把匿名函數當做函數或方法的回調使用,事實上,很多PHP函數都會用到匿名函數,例如,這是使用PHP匿名函數的絕佳時機。記住,閉包和其他值一樣,可以作為參數傳入其他PHP函數:

在匿名函數出現之前,要實現這樣的功能,PHP開發者只能單獨建立具名函數,然後使用名稱來引用這個函數:
function makeHelloWorld($name) { 
    $i = 0;
    return function()use($name, &$i){
        echo $name.$i. ' <br>';
        $i++;
    };

}
$hello1 = makeHelloWorld("itbsl");
$hello2 = makeHelloWorld("kevin");
$hello1();
$hello1();
$hello1();
$hello2();
這樣做把回調的實作和使用場所隔離開了,而且使用閉包實作程式碼更加簡潔。

itbsl0 
itbsl1 
itbsl2 
kevin0

建立閉包

包含自由變數的函數與為所有這些自由變數提供了變數綁定的環境一起,稱為閉包。 bindTouseuse列印結果:

從父作用域繼承變數

在PHP中必須手動呼叫閉包物件的

方法或使用

關鍵字把父作用域的變數及狀態附加到PHP閉包。而實際應用中,又以使用
Route::group(['domain' => '{account}.myapp.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});
關鍵字實現居多。

IlluminateDatabaseEloquentsaveOrFail

use關鍵字

PHP的匿名函數和閉包是什麼?如何創建?

實際上,Laravel框架中也大量使用了閉包,最常見的例如路由定義:$options

這裡面的兩個function都是匿名函數。而從父作用域繼承變數的使用場景在Laravel底層原始碼中也是俯拾即是,例如Model.php(Model)的forceFill方法:

PHP的匿名函數和閉包是什麼?如何創建?

該方法:

此方法的作用是使用事務將模型資料保存到資料庫,這裡面我們使用匿名函數返回保存狀態,同時使用use關鍵字將父作用域的傳遞給該閉包以便其能夠存取這個資料。

此外,也支援傳遞多個父作用域變數到匿名函數,例如還是在

類別中的__invoke方法:bindTo

__invoke__invoke()多個變數以逗號分隔即可。

bindTobindTobindTo方法

bindTo$this我們在前面已經提到,閉包是一個對象,所以我們可以在閉包中使用$this字取得閉包的內部狀態,閉包物件的預設狀態沒什麼用,需要注意的是其中的

魔術方法和方法。 的作用前面已經說過,當嘗試以呼叫函數的方式呼叫一個物件時, 方法會被自動呼叫。 接下來我們來看看方法,透過這個方法,我們可以把閉包的內部狀態綁定到其他物件上。這裡方法的第二個參數顯得尤為重要,其作用是指定綁定閉包的那個對象所屬的PHP類,這樣,閉包就可以在其他地方訪問邦定閉包的對像中受保護和私有的成員變數。 你會發現,PHP框架經常使用方法把路由URL映射到匿名回呼函數上,框架會把匿名回調函數綁定到應用對像上,這樣在匿名函數中就可以使用關鍵字引用重要的應用程式物件:
class App {
    protected $routes = [];
    protected $responseStatus = '200 OK';
    protected $responseContentType = 'text/html';
    protected $responseBody = 'Laravel学院';

    public function addRoute($routePath, $routeCallback) {
        $this->routes[$routePath] = $routeCallback->bindTo($this, __CLASS__);
    }

    public function dispatch($currentPath) {
        foreach ($this->routes as $routePath => $callback) {
            if( $routePath === $currentPath) {
                $callback();
            }
        }
        header('HTTP/1.1 ' . $this->responseStatus);
        header('Content-Type: ' . $this->responseContentType);
        header('Content-Length: ' . mb_strlen($this->responseBody));
        echo $this->responseBody;
    }

}

这里我们需要重点关注addRoute方法,这个方法的参数分别是一个路由路径和一个路由回调,dispatch方法的参数是当前HTTP请求的路径,它会调用匹配的路由回调。第9行是重点所在,我们将路由回调绑定到了当前的App实例上。这么做能够在回调函数中处理App实例的状态:

$app = new App();
$app->addRoute(‘user/nonfu’, function(){
    $this->responseContentType = ‘application/json;charset=utf8’;
    $this->responseBody = ‘{“name”:”LaravelAcademy"}';
});
$app->dispatch(‘user/nonfu');

在Larval底层也有用到bindTo方法,详见Illuminate\Support\Traits\Macroable__call方法:闭包和匿名函数(https://laravelacademy.org/post/4341.html)

总结:以上就是本篇文章的全部内容,希望能对大家的学习有所帮助。


陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除