本文目录导读:

在 PHP 项目中实现消息推送,根据应用场景(如实时网页消息、服务端事件通知、移动端推送)的不同,主要有以下几种主流实现方案:
使用 WebSocket(推荐用于实时双向通信)
适用于聊天、在线协作、实时通知等需要与服务器保持长连接的场景。
- 原理:在客户端和服务器之间建立一个全双工的长连接,服务器可以主动向客户端推送数据。
- PHP 实现方案:
- 原生 PHP + Swoole / Workerman:这是 PHP 实现 Websocket 最常用的方式,Swoole 和 Workerman 是常驻内存的 PHP 扩展/框架,可以突破传统 PHP 请求-响应模式的限制。
- Swoole:
Swoole\WebSocket\Server - Workerman:
Workerman\Connection\WebsocketConnection
- Swoole:
- 商业云服务:使用 Pusher、Ably 或 腾讯云、阿里云的 WebSocket 服务。
- 原生 PHP + Swoole / Workerman:这是 PHP 实现 Websocket 最常用的方式,Swoole 和 Workerman 是常驻内存的 PHP 扩展/框架,可以突破传统 PHP 请求-响应模式的限制。
- 示例(Workerman 服务器端代码):
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Worker;
use Workerman\Lib\Timer;
// 创建一个 Websocket 服务器
$ws_worker = new Worker("websocket://0.0.0.0:2346");
// 启动 4 个进程
$ws_worker->count = 4;
// 连接建立时
$ws_worker->onConnect = function($connection) {
echo "新连接\n";
};
// 收到消息时
$ws_worker->onMessage = function($connection, $data) use ($ws_worker) {
// 向所有客户端发送消息(推送)
foreach($ws_worker->connections as $client) {
$client->send($data);
}
};
// 连接断开时
$ws_worker->onClose = function($connection) {
echo "连接断开\n";
};
// 运行 worker
Worker::runAll();
- 客户端 JS:
var ws = new WebSocket("ws://your_server_ip:2346");
ws.onmessage = function (e) {
console.log("收到消息: " + e.data);
};
ws.send("Hello server!");
使用 Server-Sent Events(适合单向推送)
适用于需要服务器单向推送消息给浏览器,但不需要客户端频繁发送数据的场景(如新闻推送、股票行情、日志监控)。
- 原理:客户端通过 HTTP 连接向服务器发送一个
EventSource请求,服务器端持续输出text/event-stream格式的数据。 - 优势:实现简单,基于标准 HTTP 协议,不需要额外库(如 Swoole)或修改 Apache/Nginx 配置。
- PHP 实现(传统 PHP 脚本):
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
// 模拟数据推送循环
$counter = 0;
while (true) {
$data = json_encode(['msg' => 'Hello ' . $counter, 'time' => date('H:i:s')]);
echo "data: {$data}\n\n";
ob_flush();
flush();
sleep(2); // 每 2 秒推送一次
$counter++;
}
- 客户端 JS:
var source = new EventSource("http://your_server.com/sse.php");
source.onmessage = function (event) {
var data = JSON.parse(event.data);
console.log(data.msg);
};
- 注意:每个连接会占用一个 PHP-FPM 进程,高并发时容易撑爆,常用于低并发的管理后台或监控页面。
使用轮询机制
适用于实时性要求不高的场景(如每 3-5 秒检查一次是否有新消息)。
- 原理:客户端定时(通过
setInterval或setTimeout)向服务器发送 HTTP 请求,服务器检查是否有新数据并返回。 - 缺点:效率低,浪费带宽和服务器资源,有明显延迟。
结合消息队列实现异步推送
适用于需要解耦、高吞吐量的场景(如用户下单后通知多个系统)。
- 流程:PHP 业务逻辑将推送任务写入 Redis 列表(List)或 RabbitMQ/腾讯 CMQ 等消息队列,由独立的后台消费者进程(常驻 PHP 脚本)读取并发送。
- 生产者:用户注册后,PHP 业务代码
rpush('push_queue', json_encode(['type'=>'welcome', 'user_id'=>123]))。 - 消费者:一个使用 Workerman 或 Swoole 编写的常驻进程,从队列中取出数据,调用 WebSocket 或第三方推送 SDK 进行发送。
- 生产者:用户注册后,PHP 业务代码
移动端或跨平台推送
如果推送到手机 App(iOS/Android 或微信/钉钉),不能直接建立长连接。
- 方案:PHP 调用第三方推送服务 SDK。
- 极光推送(JPush)
- 个推
- 腾讯云移动推送(TPNS)
- Firebase Cloud Messaging(FCM)
- 阿里云移动推送
- 微信小程序 / 公众号模板消息(通过微信 API)
总结与选型建议
| 场景 | 推荐技术 | PHP 实现方式 | 并发能力 |
|---|---|---|---|
| 实时性高、双向(IM,实时协作) | WebSocket | Swoole / Workerman(或 Pusher 等云服务) | 高(长连接复用) |
| 实时性高、服务器单向推送(监控屏、大盘) | SSE | 配合 Nginx 或独立常驻进程 | 中等(每个连接一个进程) |
| 实时性较低、兼容性高(老旧系统) | AJAX 轮询 | 普通 PHP 脚本(短请求) | 低(大量请求开销) |
| 异步解耦、高吞吐(订单通知等) | 消息队列 + 消费进程 | Redis/RabbitMQ + Workerman/Swoole | 高 |
| 移动端 App / 服务号 | 第三方 SDK | 调用 HTTP API(如 JPush SDK) | 由第三方保障 |
核心建议: 如果是在传统 PHP(nginx+php-fpm)下,不建议直接用 PHP 脚本做长连接轮询或 SSE(会快速占满进程),最佳实践是引入 Swoole 或 Workerman 作为独立的推送服务,主业务 PHP 代码只需往 Redis 或消息队列里写任务即可。