深入剖析 PHP 运行模式:从 FPM-FCGI 到 CLI 及 Webman/Workerman 的高级对比

深入解析PHP运行模式:从FPM-FCGI到CLI,再到Webman/Workerman的进阶之路

在PHP开发领域,不同的运行模式决定了程序的执行逻辑、性能表现和适用场景。很多开发者入门时只接触过PHP-FPM(常被误写为fpm-fcgi)搭配Nginx/Apache的经典组合,却对CLI模式、Webman/Workerman这类常驻进程框架一知半解。本文将从核心概念入手,系统对比PHP-FPM、CLI模式的本质差异,详解Webman/Workerman的底层逻辑,并通过实战代码案例,帮你彻底理清不同运行模式的适用场景与选型思路。

一、基础认知:PHP-FPM(FPM-FCGI)—— 传统Web请求的“标配”

1.1 什么是PHP-FPM(FPM-FCGI)

PHP-FPM(FastCGI Process Manager)是PHP官方推荐的FastCGI进程管理器,本质是PHP解释器与Web服务器之间的通信桥梁。这里的FCGI(FastCGI)并非程序,而是一种通信协议,解决了传统CGI“每次请求新建进程、资源开销大”的痛点。

简单来说,PHP-FPM的核心逻辑是:

  • Web服务器(Nginx/Apache)接收用户的HTTP请求(如访问.php文件),自身不解析PHP代码,而是通过FastCGI协议将请求转发给PHP-FPM;
  • PHP-FPM维护一个进程池,复用进程处理请求,避免重复创建销毁进程的开销;
  • PHP进程执行脚本后,将结果返回给Web服务器,最终由Web服务器响应给用户。

1.2 PHP-FPM的运行特征与代码案例

PHP-FPM的生命周期与HTTP请求强绑定:请求到来时复用/新建进程,请求结束后进程回到空闲状态(或按配置销毁),全程依赖Web服务器转发。

实战案例:Nginx + PHP-FPM配置(处理普通Web请求)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Nginx核心配置片段
server {
listen 80;
server_name example.com;
root /var/www/html; # 项目根目录

# 处理PHP请求,转发给PHP-FPM
location ~ \.php$ {
# 禁止访问不存在的PHP文件(安全优化)
try_files $uri =404;
# PHP-FPM监听地址(默认9000端口,也可使用unix sock)
fastcgi_pass 127.0.0.1:9000;
# 默认入口文件
fastcgi_index index.php;
# 告诉PHP-FPM脚本的真实路径
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 加载FastCGI通用参数(如REQUEST_METHOD、GET/POST参数等)
include fastcgi_params;
}
}

对应的PHP测试脚本(/var/www/html/test.php):

1
2
3
4
5
6
7
<?php
// PHP-FPM模式下,超全局变量$_SERVER、$_GET等正常可用
echo "当前运行模式:" . php_sapi_name() . "<br>"; // 输出:fpm-fcgi
echo "请求方法:" . $_SERVER['REQUEST_METHOD'] . "<br>";
echo "GET参数id:" . ($_GET['id'] ?? '无') . "<br>";
// PHP-FPM中,脚本执行完毕即结束,无法常驻
echo "脚本执行时间:" . date('Y-m-d H:i:s');

访问http://example.com/test.php?id=100,输出示例:

1
2
3
4
当前运行模式:fpm-fcgi
请求方法:GET
GET参数id:100
脚本执行时间:2025-12-30 15:30:00

1.3 PHP-FPM的常用操作(Linux系统)

1
2
3
4
5
6
7
8
# 启动PHP-FPM
systemctl start php-fpm
# 查看运行状态
systemctl status php-fpm
# 修改配置后平滑重启(不中断现有请求)
systemctl reload php-fpm
# 停止PHP-FPM
systemctl stop php-fpm

二、核心进阶:PHP-CLI模式—— 脱离Web服务器的“独立运行”

2.1 什么是PHP-CLI

CLI(Command Line Interface)即PHP的命令行运行模式,是PHP两大核心运行模式(Web模式、CLI模式)之一,与PHP-FPM(Web模式)的核心差异在于:

  • 运行入口:无需Web服务器转发,直接通过终端执行PHP脚本;
  • 生命周期:由脚本自身控制,可“一次性执行完毕退出”,也可“常驻内存不退出”;
  • 环境隔离:CLI模式下无超全局变量(如$_SERVER$_POST),需通过命令行参数、标准输入输出交互。

2.2 CLI模式的基础使用(代码案例)

案例1:简单的CLI脚本(一次性执行)

创建cli_demo.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
/**
* PHP-CLI模式基础示例
*/
// 1. 获取CLI模式下的命令行参数($argv是数组,$argv[0]是脚本名)
$args = $argv;
echo "当前运行模式:" . php_sapi_name() . "\n"; // 输出:cli
echo "脚本名称:" . $args[0] . "\n";
echo "传入的参数:" . implode(', ', array_slice($args, 1)) . "\n";

// 2. 标准输入输出交互
echo "请输入你的名字:";
$name = fgets(STDIN); // 读取终端输入
echo "你好," . trim($name) . "!CLI脚本执行完毕\n";

// 3. CLI模式下的超时控制(默认无超时,可手动设置)
set_time_limit(0); // 取消脚本执行时间限制(常驻进程必备)

终端执行命令及输出示例:

1
2
3
4
5
6
7
8
9
# 执行脚本并传入参数
php cli_demo.php 100 test

# 输出结果
当前运行模式:cli
脚本名称:cli_demo.php
传入的参数:100, test
请输入你的名字:张三
你好,张三!CLI脚本执行完毕

案例2:CLI常驻进程(模拟长连接)

创建cli_daemon.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
/**
* CLI模式下的常驻进程示例
*/
set_time_limit(0); // 取消超时限制
ignore_user_abort(true); // 忽略用户中断(如Ctrl+C)

$count = 0;
// 无限循环,实现常驻
while (true) {
$count++;
echo "进程运行中,计数:{$count},时间:" . date('Y-m-d H:i:s') . "\n";
sleep(1); // 休眠1秒,避免CPU占用过高

// 可选:计数到10时退出(模拟常驻进程的手动终止逻辑)
if ($count >= 10) {
echo "进程达到终止条件,退出\n";
break;
}
}

终端执行及输出:

1
2
3
4
5
6
7
8
php cli_daemon.php

# 输出结果
进程运行中,计数:1,时间:2025-12-30 15:40:00
进程运行中,计数:2,时间:2025-12-30 15:40:01
...
进程运行中,计数:10,时间:2025-12-30 15:40:09
进程达到终止条件,退出

三、高级应用:Webman/Workerman—— 基于CLI的高性能常驻进程框架

3.1 核心定位:解决PHP-FPM的“短板”

PHP-FPM适合处理短连接、同步HTTP请求,但面对WebSocket、TCP长连接、即时通讯、定时任务、高并发API 等场景时,存在天然缺陷:

  • 无法维持长连接:HTTP短连接特性导致无法实现实时通讯;
  • 进程开销:每次请求需复用/创建进程,高并发下性能瓶颈明显;
  • 异步能力弱:PHP-FPM默认同步执行,处理IO密集型任务(如数据库查询、接口调用)时会阻塞。

而Workerman(底层)和Webman(上层封装)正是为解决这些问题而生——基于PHP-CLI模式的常驻进程框架,核心优势是“长连接、异步、高并发”。

3.2 Workerman:PHP编写的高性能网络框架

Workerman是纯PHP开发的常驻进程框架,无需PHP-FPM,直接通过CLI启动,支持HTTP、TCP、UDP、WebSocket等协议。

实战案例:Workerman实现WebSocket即时通讯

步骤1:安装Workerman
1
2
3
4
5
6
7
# 安装Composer(已安装可跳过)
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

# 创建项目并安装Workerman
mkdir workerman-demo && cd workerman-demo
composer require workerman/workerman
步骤2:编写WebSocket服务端(start.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
/**
* Workerman WebSocket服务端示例
*/
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Worker;

// 创建WebSocket服务,监听0.0.0.0:8282端口
$ws_worker = new Worker("websocket://0.0.0.0:8282");

// 设置进程数(根据CPU核心数调整)
$ws_worker->count = 4;

// 当客户端连接成功时触发
$ws_worker->onConnect = function ($connection) {
echo "客户端[" . $connection->id . "]连接成功\n";
};

// 当收到客户端消息时触发
$ws_worker->onMessage = function ($connection, $data) {
echo "收到客户端[" . $connection->id . "]消息:{$data}\n";
// 向客户端回复消息
$connection->send("服务端已收到:{$data},时间:" . date('Y-m-d H:i:s'));
};

// 当客户端断开连接时触发
$ws_worker->onClose = function ($connection) {
echo "客户端[" . $connection->id . "]断开连接\n";
};

// 启动Worker(CLI模式下常驻)
Worker::runAll();
步骤3:启动服务(CLI模式)
1
2
3
4
5
6
7
8
9
10
11
# 前台启动(调试用)
php start.php start

# 后台常驻启动(生产环境)
php start.php start -d

# 停止服务
php start.php stop

# 查看状态
php start.php status
步骤4:编写WebSocket客户端(client.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket客户端</title>
</head>
<body>
<input type="text" id="msg" placeholder="输入消息">
<button onclick="sendMsg()">发送</button>
<div id="log"></div>

<script>
// 连接Workerman WebSocket服务
var ws = new WebSocket("ws://你的服务器IP:8282");

// 连接成功回调
ws.onopen = function() {
log("连接服务端成功");
};

// 接收服务端消息
ws.onmessage = function(e) {
log("服务端回复:" + e.data);
};

// 连接关闭回调
ws.onclose = function() {
log("与服务端的连接断开");
};

// 发送消息函数
function sendMsg() {
var msg = document.getElementById("msg").value;
if (!msg) return;
ws.send(msg);
document.getElementById("msg").value = "";
log("发送消息:" + msg);
}

// 日志输出
function log(text) {
var logDiv = document.getElementById("log");
logDiv.innerHTML += text + "<br>";
}
</script>
</body>
</html>

访问client.html,输入消息发送,服务端终端会实时打印客户端连接、消息、断开等日志,实现真正的长连接即时通讯——这是PHP-FPM无法做到的。

3.3 Webman:更贴近传统MVC的Workerman封装

Webman基于Workerman开发,保留了常驻进程的高性能,同时适配传统PHP开发者的MVC开发习惯,无需关注底层网络细节,专注业务逻辑。

实战案例:Webman创建HTTP接口

步骤1:安装Webman
1
2
3
# 创建Webman项目
composer create-project workerman/webman webman-demo
cd webman-demo
步骤2:编写接口控制器(app/controller/IndexController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
namespace app\controller;

use support\Request;

class IndexController
{
/**
* Webman HTTP接口示例
*/
public function index(Request $request)
{
// 获取GET参数
$id = $request->get('id', 0);
// 模拟业务逻辑(无阻塞,支持异步)
$data = [
'code' => 200,
'msg' => 'success',
'data' => [
'id' => $id,
'time' => date('Y-m-d H:i:s'),
'mode' => php_sapi_name() // 输出:cli
]
];
// 返回JSON响应
return json($data);
}

/**
* Webman定时任务示例(常驻进程天然支持)
*/
public function cron()
{
// 无需依赖crontab,Webman可直接实现定时任务
static $count = 0;
$count++;
echo "定时任务执行第{$count}次,时间:" . date('Y-m-d H:i:s') . "\n";
return json(['code' => 200, 'msg' => '定时任务执行成功']);
}
}
步骤3:启动Webman(CLI模式)
1
2
3
4
5
# 前台启动
php start.php start

# 后台启动
php start.php start -d
步骤4:访问接口

访问http://你的服务器IP:8787/index/index?id=100,返回JSON:

1
2
3
4
5
6
7
8
9
{
"code": 200,
"msg": "success",
"data": {
"id": 100,
"time": "2025-12-30 16:00:00",
"mode": "cli"
}
}

Webman无需Nginx转发即可直接处理HTTP请求(也可配置Nginx做反向代理优化),且支持异步任务、定时任务、WebSocket等特性,性能远超PHP-FPM。

四、核心对比:PHP-FPM vs CLI(Webman/Workerman)

维度 PHP-FPM(FPM-FCGI) PHP-CLI(原生) Webman/Workerman(CLI进阶)
运行模式 Web模式,依赖Web服务器转发 命令行模式,独立运行 基于CLI的常驻进程模式,独立运行
进程生命周期 与HTTP请求绑定(单次/复用) 可一次性执行,也可手动常驻 常驻进程(启动后一直运行)
核心协议 FastCGI 无固定协议(终端交互) HTTP/TCP/UDP/WebSocket
超全局变量 支持($$_SERVER$$_GET/$_POST等) 不支持(需通过$argv/STDIN获取参数) 封装后支持(如Webman的Request对象)
连接类型 短连接(HTTP) 无固定连接类型 长连接(WebSocket/TCP)+ 短连接(HTTP)
异步/并发能力 弱(默认同步,高并发易阻塞) 需手动实现 强(原生支持异步IO、协程)
适用场景 普通Web网站、管理后台、电商页面 脚本工具、定时任务(简单场景) 即时通讯、TCP服务、高并发API、物联网
启动命令 systemctl start php-fpm php xxx.php php start.php start -d

五、选型建议:该用哪种模式?

  1. 普通Web场景:优先选PHP-FPM + Nginx,生态成熟、部署简单,满足90%的常规网站需求(如WordPress、Laravel项目);
  2. 长连接/高并发场景:选Webman/Workerman(CLI模式),比如即时聊天工具、直播弹幕、物联网设备通信、高并发API接口;
  3. 脚本/工具场景:选原生PHP-CLI,比如数据清洗脚本、定时任务(简单场景)、命令行工具;
  4. 混合场景:可同时部署PHP-FPM(处理常规Web请求)和Webman(处理WebSocket长连接),各司其职。

总结

  1. PHP-FPM(FPM-FCGI)是传统Web场景的标配,基于FastCGI协议与Web服务器协作,生命周期绑定HTTP请求;
  2. PHP-CLI是脱离Web服务器的命令行模式,可灵活控制脚本生命周期,是常驻进程框架的基础;
  3. Webman/Workerman是CLI模式的进阶应用,解决了PHP-FPM长连接、高并发、异步的短板,适合实时通讯、TCP服务等场景;
  4. 选型核心是“匹配业务场景”:常规Web用FPM,长连接/高并发用Webman/Workerman,脚本工具用原生CLI。

通过理解不同运行模式的本质,你可以根据业务需求选择最适合的技术方案,既不盲目追求“高性能框架”,也不局限于传统模式的短板,让PHP发挥出最大的价值。