libev 是一個高效能、功能完整的事件循環庫(C 語言實作),提供 epoll/kqueue/IOCP 等多平台非同步 I/O 多路複用抽象。PHP ev 擴充套件(PECL)為其提供原生介面,適用於長連線服務、即時推播、微服務閘道等高併發場景。
# Ubuntu/Debian
sudo apt-get install libev-dev
sudo pecl install ev
echo "extension=ev.so" > /etc/php/8.x/mods-available/ev.ini
sudo phpenmod ev
<?php
// 1. 單次觸發:2 秒後執行
$w1 = new EvTimer(2, 0, function () {
echo "2 秒後觸發一次\n";
});
// 2. 週期觸發:2 秒後首次,之後每 1 秒
$w2 = new EvTimer(2, 1, function ($w) {
echo "每秒觸發,迭代次數:" . Ev::iteration() . "\n";
if (Ev::iteration() >= 5) $w->stop(); // 5 次後停止
});
// 3. 建立但不啟動:稍後手動 start()
$w_stopped = EvTimer::createStopped(10, 5, function ($w) {
echo "手動啟動的定時器\n";
if (Ev::iteration() >= 2) $w->stop();
});
// 啟動事件循環(阻塞直到所有 watcher 停止)
Ev::run();
// 手動啟動第三個定時器,單次迭代
$w_stopped->start();
echo "單次迭代\n";
Ev::run(Ev::RUN_ONCE);
// 重啟第二個定時器,非阻塞模式
$w2->again();
Ev::run(Ev::RUN_NOWAIT);
// 新增一個長時間阻塞定時器,演示阻塞循環
$w = new EvTimer(10, 0, function() {});
echo "阻塞循環中...\n";
Ev::run();
echo "END\n";
<?php
error_reporting(E_ERROR); // 屏蔽 sockets 擴充的非阻塞警告
$eNonBlocking = [11, 115]; // EAGAIN/EWOULDBLOCK, EINPROGRESS
$port = getservbyname('www', 'tcp');
$host = 'google.com';
$ip = gethostbyname($host);
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($socket);
// 10 秒總超時監視器
$timeout = new EvTimer(10, 0, function () use ($socket) {
socket_close($socket);
Ev::stop(Ev::BREAK_ALL);
});
// 可寫監視器:連線成功後發送請求
$writeWatcher = new EvIo($socket, Ev::WRITE, function ($w) use ($socket, $timeout, $eNonBlocking) {
$timeout->stop();
$w->stop();
$req = "HEAD / HTTP/1.1\r\nHost: $host\r\nConnection: Close\r\n\r\n";
if (!socket_write($socket, $req, strlen($req))) {
trigger_error("寫入失敗", E_USER_ERROR);
}
// 可讀監視器:接收回應
$readWatcher = new EvIo($socket, Ev::READ, function ($w, $re) use ($socket, $eNonBlocking) {
$ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);
if ($ret > 0) {
echo $out;
} elseif ($ret === 0) { // 連線關閉
$w->stop();
socket_close($socket);
return;
}
// 非阻塞暫無資料
if (in_array(socket_last_error(), $eNonBlocking)) return;
$w->stop();
socket_close($socket);
});
Ev::run(); // 進入子循環處理讀取
});
socket_connect($socket, $ip, $port); // 非阻塞連線,立即返回
Ev::run(); // 啟動主循環
| 常數 | 行為 |
|---|---|
Ev::RUN | 預設:阻塞直到無 watcher 或 `Ev::stop()` |
Ev::RUN_ONCE | 單次輪詢:處理就緒事件後返回 |
Ev::RUN_NOWAIT | 非阻塞:檢查就緒事件立即返回 |
| 特性 | ext-ev | Swoole | Workerman | ReactPHP |
|---|---|---|---|---|
| 實作層級 | C 擴充(最底層) | C 擴充(內建 Server/Coroutine) | 純 PHP(stream_select) | 純 PHP(stream_select) |
| 協程支援 | 無(需自行實作) | 原生協程 | 無 | Promise/Await |
| 適用場景 | 嵌入式、CLI 工具、輕量代理 | 高併發 Server、WebSocket、微服務 | 快速開發長連線服務 | 元件化、框架整合 |
libev 為 PHP 帶來了真正的非阻塞事件驅動能力。雖無內建協程,但作為底層引擎極其穩定高效。適合開發自訂協議伺服器、高效能代理、監控代理等場景。若需快速構建業務 Server,建議直接使用 Swoole 或 Workerman。