PHP 從 4.3 版本引入 CLI SAPI,配合 pcntl (進程控制) 和 posix (POSIX 函數) 擴展,可編寫長運行的守護進程、信號處理、多進程並發程序。
function run() {
// 第一次 fork:父進程退出,子進程成為孤兒進程,由 init 收養
if (($pid1 = pcntl_fork()) === 0) {
// 子進程:創建新會話,脫離終端控制
posix_setsid();
// 第二次 fork:防止會話首進程重新獲得控制終端
if (($pid2 = pcntl_fork()) === 0) {
// 真正的守護進程:執行業務邏輯
handle_http_request('0.0.0.0', 9999);
} else {
// 第一子進程退出
exit(0);
}
} else {
// 父進程等待第一子進程退出
pcntl_wait($status);
}
}
function handle_http_request($address, $port) {
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, $address, $port);
socket_listen($socket, 16); // backlog
$response = "HTTP/1.1 200 OK\r\n" .
"Content-Length: 15\r\n" .
"Content-Type: text/plain; charset=UTF-8\r\n\r\n" .
"PHP HTTP Server";
$resLen = strlen($response);
while (true) {
$client = socket_accept($socket);
if ($client !== false) {
socket_write($client, $response, $resLen);
socket_close($client);
}
}
}
| 階段 | 目的 | ||
|---|---|---|---|
| 第一次 Fork | 父進程退出,Shell 以為任務結束;子進程繼續運行 | ||
| setsid() | 脫離終端,創建新會話 | ||
| 第二次 Fork | 確保守護進程不是會話首進程,防止意外獲得控制終端 |
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| PHP pcntl 守護進程 | 原生、無依賴、完全控制 | 代碼複雜、單進程併發弱、需自行處理信號/僵屍進程 | 學習、簡單服務、嵌入式 |
| Swoole / Workerman | 高性能異步、多進程、協程、內置 HTTP/WebSocket/TCP | 需安裝擴展、學習曲線 | 高併發、長連接、微服務、生產首選 |
| ReactPHP / Amp | 純 PHP 異步、無擴展依賴 | 性能受限於 PHP 引擎 | 不想裝擴展的異步場景 |
| systemd + PHP-FPM | 標準化、穩定、生態成熟 | 請求響應模式、非長連接 | 傳統 Web 應用 |
PHP 編寫守護進程核心技術棧:CLI SAPI + pcntl + posix + sockets。雙重 Fork + setsid 是經典 Unix 守護進程模式。現代生產環境強烈建議使用 Swoole 或 Workerman,獲得數量級性能提升和豐富的網絡編程抽象。理解底層原理有助於排查框架層面的疑難雜症。