PHP+Swoole的閉包寫法
PHP+Swoole的閉包寫法
2016年10月25日韓 天峰
JS程式設計師總是嘲笑PHP沒有閉包,今天抽空寫一篇文章來專門介紹一下PHP的閉包。從5.3版本開始PHP就增加了匿名函式支援,經過數個版本迭代到現在的PHP5.6、PHP7,PHP語言的閉包已經非常完善了。再結合Swoole提供的事件驅動支援,PHP的閉包功能非常強大而且很優雅。
匿名函式
匿名函式是閉包的核心,匿名函式在PHP裡實際上是一個Closure類的物件(請注意是物件)。與普通的物件導向程式設計方式不同,匿名函式的程式碼是直接寫在呼叫處的,不需要額外寫一個類,編寫方法的程式碼。這樣的好處就是更直接。下面的示例是設定一個定時器,每2秒輸出hello world。
傳統寫法
function timer () {
echo "hello world";
}
Swoole\Timer::tick(2000, 'timer');
閉包寫法
Swoole\Timer::tick(2000, function () {
echo "hello world";
});
非閉包的傳統寫法,先要宣告一個函式,再轉入函式名稱字串。兩段程式碼是分離的,不夠直觀。而閉包的寫法把定時器的宣告和定時器要執行的程式碼寫在了一起,邏輯非常清晰直觀。使用閉包語法可以很方便編寫回撥函式。在事件驅動程式設計、排序、array_walk等需要使用者傳入一段執行程式碼的場景中,閉包的寫法非常優雅。
閉包更強大的地方在於它可以直接在呼叫處引入外部變數。PHP中實現的方法就是use關鍵詞。
Use語法
如果剛才的定時器需要傳入一個變數,傳統的寫法只能通過全域性變數來實現。與JS不同,PHP的變數引入是顯式的,如果要引用外部變數必須使用use來宣告。而JS是隱式的,匿名函式內部可以隨意操作外部變數,無需宣告。這樣好處是少寫了一點程式碼,缺點是存在風險和混亂。
傳統寫法
$str = "hello world";
function timer () {
global $str;
echo $str;
}
Swoole\Timer::tick(2000, 'timer');
閉包寫法
$str = "hello world";
Swoole\Timer::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 Swoole\Server {
function onReceive($serv, $fd, $reactorId, $data) {
$db->query($sql, function ($queryId, $queryResult) use ($fd) {
$this->send($fd, $queryResult);
}
}
}
另外如果希望在閉包函式中修改外部變數,可以在use時為變數增加&引用符號即可。注意物件型別不需要加&,因為在PHP中物件預設就是傳引用而非傳值。
相關文章
- [JS]閉包和詞法環境JS
- 二分查詢的左閉右開和左閉右閉寫法
- 【Python語法】循序漸進理解閉包Python
- 什麼是閉包,閉包的優缺點?
- 閉包的起源
- JavaScript 的閉包JavaScript
- 什麼是閉包?閉包的作用是什麼?
- js閉包及閉包的經典使用場景JS
- [JavaScript閉包]Javascript閉包的判別,作用和示例JavaScript
- 閉包
- Swift-逃逸閉包、自動閉包Swift
- 閉包 | 淺談JavaScript閉包問題JavaScript
- js閉包的理解JS
- js中的閉包JS
- PHP 閉包的理解PHP
- 閉包的含義
- 理解Javascript的閉包JavaScript
- Go | 閉包的使用Go
- 【集合論】關係閉包 ( 關係閉包求法 | 關係圖求閉包 | 關係矩陣求閉包 | 閉包運算與關係性質 | 閉包複合運算 )矩陣
- weiphp不能夠使用閉包方式進行路由重寫PHP路由
- 關閉mac輸入法首字母大寫Mac
- 閉包是什麼?怎麼形成一個閉包?為什麼使用閉包?
- Swift 閉包Swift
- golang 閉包Golang
- 「閉包」攻略
- PHP 閉包PHP
- JavaScript閉包JavaScript
- JavaScript - 閉包JavaScript
- Golang閉包Golang
- JavaScript 閉包JavaScript
- 理解“閉包”
- 理解 JavaScript 中的閉包JavaScript
- 對javascript閉包的理解JavaScript
- Go 閉包的實現Go
- 閉包方法的學習
- Golang中閉包的理解Golang
- 對JS閉包的理解JS
- JS中的 閉包(Closure)JS