本文目录导读:

- 方案一:Server-Sent Events (SSE) — 轻量级,单向推送
- 方案二:WebSocket — 双向实时通信
- 方案三:轮询 (Polling) — 简单但低效
- 方案四:长轮询 (Long Polling) — 兼容性好,延迟较低
- 方案五:第三方推送服务 — 省时省力
- 总结建议
在PHP项目中实现消息推送,通常有以下几种主流方案,你可以根据实时性要求、并发量、技术栈来选择:
Server-Sent Events (SSE) — 轻量级,单向推送
- 原理:客户端通过 HTTP 长连接订阅服务端事件,服务端可以持续推送数据(文本格式)。
- 优点:原生支持,无需引入额外库;基于 HTTP,兼容性好(除了 IE)。
- 缺点:单向(只能服务端推送给客户端);连接数受限于 Web 服务器(如 PHP-FPM 的进程数)。
适用场景:通知、股票价格更新、日志流等不需要客户端发送数据的单向推送。
PHP 示例(使用原生 PHP 作为服务端):
// server.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
// 模拟持续推送数据
while (true) {
$data = ['message' => '当前时间: ' . date('Y-m-d H:i:s'), 'id' => uniqid()];
echo "event: message\n";
echo "data: " . json_encode($data) . "\n\n";
ob_flush();
flush();
sleep(2); // 每 2 秒推送一次
}
前端(JS)订阅:
const eventSource = new EventSource('/server.php');
eventSource.addEventListener('message', function(e) {
const data = JSON.parse(e.data);
console.log(data.message);
});
WebSocket — 双向实时通信
- 原理:全双工通信协议,客户端和服务端都可以主动发送数据。
- 优点:真正的实时双向通信;性能高(连接数远高于 SSE)。
- 缺点:需要额外的 WebSocket 服务器(PHP 本身不适合做长连接守护进程,通常用 Node.js、Go、Swoole 等)。
在 PHP 中的实现方式:
方式 A:使用 Swoole(推荐) Swoole 是一个 PHP 扩展,让 PHP 拥有常驻内存、协程、WebSocket 等能力。
# 安装 Swoole 扩展 pecl install swoole
服务端代码(websocket_server.php):
use Swoole\WebSocket\Server;
$server = new Server("0.0.0.0", 9502);
$server->on('open', function (Server $server, $request) {
echo "连接建立: {$request->fd}\n";
});
$server->on('message', function (Server $server, $frame) {
echo "收到消息: {$frame->data}\n";
// 向所有客户端广播
foreach ($server->connections as $fd) {
$server->push($fd, "Server回复: " . $frame->data);
}
});
$server->on('close', function (Server $server, $fd) {
echo "连接关闭: {$fd}\n";
});
$server->start();
客户端(JS):
const ws = new WebSocket('ws://localhost:9502');
ws.onmessage = function(event) {
console.log(event.data);
};
ws.send('Hello from client');
方式 B:使用 Ratchet(基于 ReactPHP) 如果你不想安装 Swoole(非扩展方式),可以用 Ratchet。
composer require cboden/ratchet
轮询 (Polling) — 简单但低效
- 原理:前端每隔几秒向服务器发送 HTTP 请求询问是否有新消息。
- 优点:实现最简单,任何 PHP 环境都能用。
- 缺点:大量无效请求,延迟较高,不推荐用于高实时性场景。
前端(JS):
setInterval(async () => {
const response = await fetch('/get-new-messages.php');
const data = await response.json();
if (data.length > 0) {
// 处理新消息
}
}, 5000); // 每5秒轮询
PHP 服务端:
// get-new-messages.php $lastTime = $_GET['last_time'] ?? 0; // 查询数据库,获取比 $lastTime 更新的消息 $newMessages = getNewMessagesFromDb($lastTime); echo json_encode($newMessages);
长轮询 (Long Polling) — 兼容性好,延迟较低
- 原理:客户端发起请求后,服务端如果有新消息就立即返回,否则保持连接直到有新消息或超时,然后客户端重新发起请求。
- 优点:比普通轮询减少了很多无用请求;无需特殊协议。
- 缺点:仍然占用服务端连接;PHP-FPM 进程数有限,不适合大规模长连接。
示例思路:
// long-polling.php
set_time_limit(0); // 不限制执行时间,但可以根据需要设置
$maxWaitTime = 30; // 最多等待30秒
$startTime = time();
while (true) {
$newMessage = checkForNewMessage();
if ($newMessage) {
echo json_encode($newMessage);
break;
}
if ((time() - $startTime) > $maxWaitTime) {
echo json_encode(['status' => 'timeout']);
break;
}
sleep(1); // 避免 CPU 空转
}
第三方推送服务 — 省时省力
- 原理:使用专业的推送服务(如 Pusher、Firebase Cloud Messaging、GoEasy等),PHP 作为后端只负责触发推送。
- 优点:几乎零开发成本;高可用、高并发;支持更多端(Web、移动端、微信小程序等)。
- 缺点:需要付费;数据经过第三方。
示例(使用 Pusher):
composer require pusher/pusher-php-server
PHP 触发推送:
$pusher = new Pusher\Pusher('key', 'secret', 'app_id');
$pusher->trigger('my-channel', 'my-event', ['message' => 'Hello World']);
前端监听:
<script src="https://js.pusher.com/7.0/pusher.min.js"></script>
<script>
var pusher = new Pusher('key', { cluster: 'mt1' });
var channel = pusher.subscribe('my-channel');
channel.bind('my-event', function(data) {
alert(data.message);
});
</script>
总结建议
| 需求场景 | 推荐方案 | 备注 |
|---|---|---|
| 简单通知、页面内更新 | SSE | 最简单,原生支持 |
| 游戏、聊天室、协同编辑 | Swoole WebSocket | 性能最佳,需安装扩展 |
| 不想改服务器环境 | 长轮询 或 第三方服务 | 兼容性好 |
| 高并发、稳定可靠 | 第三方服务(Pusher等) | 省心但付费 |
| 企业级项目、已有 Swoole 团队 | Swoole WebSocket | 自建可控 |
特别提醒:PHP 传统的 php-fpm 模式下,每个请求都是独立的进程,不适合长连接(SSE 和长轮询会占用进程),如果并发需求高,建议使用 Swoole 或 Workerman 这类常驻内存的框架。