Sitemap

ReactPHP 深入淺出

5 min readJun 19, 2023

--

Photo by Ben Griffiths on Unsplash

前言

最近開始研究 php 非同步請求,發現有個好用的套件叫 ReactPHP,於是寫篇文章記錄使用方式跟運作原理。

非同步的套件還有其他的(像是 swoole),這篇文章只介紹 ReactPHP。
文章裡會先介紹重要的非同步元件 promise, async 和 event loop。

ReactPHP 簡介

ReactPHP 是一個在 php 實作非同步 promise 的套件,用起來蠻方便,如果有用過 nodejs 非同步,會發現兩個寫法蠻像。

nodejs

const res = await doSomething()

php

$res = await(doSomething);

ReactPHP 拆分了不同元件,有 promise, async, event-loop 還有其他的這邊就不介紹。

promise

promise 實作了 CommonJS Promise/A,裡面物件就兩個 Deffered 和 Promise。

Deferred:用來當做一個尚未完成的工作,可能會在未來某個時間點完成,裡面都會包一個 Promise。

Promise:任務本身。

使用方式

function doSomethingPromise() {
$deferred = new React\Promise\Deferred();
// Execute a Node.js-style function using the callback pattern
doSomethingAsynchronously(function (\Throwable $error, $result) use ($deferred) {
if ($error) {
$deferred->reject($error);
} else {
$deferred->resolve($result);
}
});
return $deferred->promise()
}
doSomethingPromise()
->then(
function ($value) {
// Deferred resolved, do something with $value
},
function (\Throwable $reason) {
// Deferred rejected, do something with $reason
}
);

async

提供類似 nodejs async / await 的使用方式,還有實作較複雜的功能,像是 coroutine 或是 parallel。

使用方式


$promise = React\Async\async(function () {
doSomething();
})();
$result = React\Async\await($promise);
// or
$promise->then(function () {
// success
}, function (Exception $e) {
// error
});

// coroutine
$promise = React\Async\coroutine(function () {
doSomething();
});

// parallel
React\Async\parallel([
doSomething1(),
doSomething2(),
doSomething2(),
])->then(function () {
// success
}, function (Exception $e) {
// error
});

event loop

實作 event loop 非同步的核心和 Timer。

使用方式



use React\EventLoop\Loop;

$timer = Loop::addPeriodicTimer(0.1, function () {
echo ‘Tick’ . PHP_EOL;
});

Loop::addTimer(1.0, function () use ($timer) {
Loop::cancelTimer($timer);
echo ‘Done’ . PHP_EOL;
});

ReactPHP 如何實作 async 和非同步?

因為 php 屬於腳本語言,有由上往下的執行順序,每個功能也都是同步執行,所以先前看到這個套件,就很好奇是如何實作非同步。

如果有用 nodejs 看到 async / await 會覺得是非同步,但其實在 ReactPHP 這邊,只用 Async 裡面的 async / await 或是其他功能其實並沒有非同步,如文件上說明的會需要使用 loop 才行,不過這是為什麼呢?

主要是 Async 裡面的功能是延伸 php Fiber(Fiber 可以暫停程式執行,並可以手動繼續),但這不會達到非同步的效果。

非同步的實作是在 event loop,可以從 event loop Factory 看到https://github.com/reactphp/event-loop/blob/1.x/src/Factory.php ,可以安裝其他的 event loop 套件,如 libuv, libev 的套件,或是使用預設的 [stream_select()](https://www.php.net/manual/en/function.stream-select.php)。

結論

這篇文章分享 ReactPHP 的使用方法和套件非同步的實作方式,希望對考慮在 php 裡加入非同步的 I/O 的同學有幫助。

參考

https://github.com/reactphp/reactphp
https://php.net/manual/en/class.fiber.php
https://github.com/swoole/swoole-src

--

--

No responses yet