匿名函數是閉包的核心,匿名函數在PHP里實際上是一個Closure類的對象(請注意是對象)。與普通的面向對象編程方式不同,匿名函數的代碼是直接寫在調用處的,不需要額外寫一個類,編寫方法的代碼。這樣的好處就是更直接。下面的示例是設置一個定時器,每2秒輸出hello world。
傳統寫法
function timer () { echo "hello world"; } SwooleTimer::tick(2000, 'timer');
閉包寫法
SwooleTimer::tick(2000, function () { echo "hello world"; });
非閉包的傳統寫法,先要聲明一個函數,再轉入函數名稱字符串。兩段代碼是分離的,不夠直觀。而閉包的寫法把定時器的聲明和定時器要執行的代碼寫在了一起,邏輯非常清晰直觀。使用閉包語法可以很方便編寫回調函數。在事件驅動編程、排序、array_walk等需要用戶傳入一段執行代碼的場景中,閉包的寫法非常優雅。
閉包更強大的地方在于它可以直接在調用處引入外部變量。PHP中實現的方法就是use關鍵詞。
如果剛才的定時器需要傳入一個變量,傳統的寫法只能通過全局變量來實現。與JS不同,PHP的變量引入是顯式的,如果要引用外部變量必須使用use來聲明。而JS是隱式的,匿名函數內部可以隨意操作外部變量,無需聲明。這樣好處是少寫了一點代碼,缺點是存在風險和混亂。
傳統寫法
$str = "hello world"; function timer () { global $str; echo $str; } SwooleTimer::tick(2000, 'timer');
閉包寫法
$str = "hello world"; SwooleTimer::tick(2000, function () use ($str) { echo $str; });
閉包寫法使用use直接引入了當前的$str變量,而不需要使用global全局變量。另外如果是在swoole的事件驅動編程模式,使用global就無法實現異步并發了,因為global全局變量只有1個,如果同時有多個客戶端請求,每個請求要查詢數據庫,輸出不同的內容,傳統的編程方法就不太容易實現,需要使用全局變量數組,以客戶端的ID為KEY保存各自的數據。
傳統寫法
$requestArray = array(); $dbResultArray = array(); function my_request($request, $response) { global $dbResultArray, $requestArray; $queryId = $db->query($sql, 'get_result'); $requestArray[$request->fd] = array($request, $response); $dbResultArray[$queryId] = $request->fd; } function get_result($queryId, $queryResult) { global $dbResultArray, $requestArray; list($request, $response) = $requestArray[$dbResultArray[$queryId]]; $response->end($queryResult); } $server->on('request', 'my_request');
閉包寫法
$server->on('request', function ($request, $response) { $queryId = $db->query($sql, function ($queryId, $queryResult) use ($request, $response) { $response->end($queryResult); }); });
傳統的寫法非常復雜,需要反復多次從全局數組保存/提取數據。而閉包的寫法非常簡潔優雅,只用了幾行代碼就實現了同樣的功能。閉包寫法非常適合用來編寫異步非阻塞回調模式的服務器程序。目前熱門的編程語言中只有PHP和JS具備這種能力。
在類的方法中使用匿名函數,5.4以上的版本無需使用use引入$this,直接可以在匿名函數中使用$this來調用當前對象的方法。在swoole編程中,可以利用此特性減少$serv對象的use引入傳遞。
class Server extends SwooleServer { function onReceive($serv, $fd, $reactorId, $data) { $db->query($sql, function ($queryId, $queryResult) use ($fd) { $this->send($fd, $queryResult); } } }
另外如果希望在閉包函數中修改外部變量,可以在use時為變量增加&引用符號即可。注意對象類型不需要加&,因為在PHP中對象默認就是傳引用而非傳值。
更多PHP相關知識,請訪問PHP中文網!
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com