本文目录导读:

- 方案一:WebSocket(推荐)
- 方案二:SSE (Server-Sent Events)
- 方案三:短轮询 + HTTP
- 方案四:第三方推送服务
- 方案五:长轮询 (Long Polling)
- 综合推荐
- 实际项目最佳实践
在 PHP 项目中实现实时通知功能,通常需要结合前端实时通信技术和后端消息推送机制,由于 PHP 本身是同步阻塞的 HTTP 协议,无法原生维持长连接,因此需要借助以下主流方案:
WebSocket(推荐)
这是最直接、最实时的方案,PHP 服务端通过 WebSocket 协议与客户端建立双向长连接。
技术选型
- Swoole:高性能异步 PHP 扩展,支持 WebSocket 服务器
- Workerman:纯 PHP 实现的多进程 socket 框架
- Ratchet:基于 ReactPHP 的 WebSocket 组件库
实现步骤(以 Workerman 为例)
安装 Workerman
composer require workerman/workerman
创建 WebSocket 服务端
// server.php
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
$ws_worker = new Worker('websocket://0.0.0.0:8080');
// 维护用户连接映射
$user_connections = [];
$ws_worker->onConnect = function ($connection) {
echo "新连接\n";
};
$ws_worker->onMessage = function ($connection, $data) use (&$user_connections) {
$msg = json_decode($data, true);
// 客户端发送认证消息 {'type': 'auth', 'user_id': 1}
if ($msg['type'] === 'auth') {
$user_connections[$msg['user_id']] = $connection;
$connection->userId = $msg['user_id'];
echo "用户 {$msg['user_id']} 已认证\n";
}
// 其他业务消息处理...
};
$ws_worker->onClose = function ($connection) use (&$user_connections) {
if (isset($connection->userId)) {
unset($user_connections[$connection->userId]);
echo "用户 {$connection->userId} 断开\n";
}
};
Worker::runAll();
客户端 JS 代码
// 前端连接 WebSocket
let ws = new WebSocket('ws://your-domain.com:8080');
ws.onopen = function() {
// 发送用户认证
ws.send(JSON.stringify({
type: 'auth',
user_id: 123 // 当前登录用户ID
}));
};
ws.onmessage = function(event) {
let data = JSON.parse(event.data);
console.log('收到通知:', data);
showNotification(data);
};
从 PHP 业务代码推送消息 需要将 WebSocket 服务端与 HTTP 端连通,常见做法:
- 使用内部消息队列(Redis Pub/Sub)
- 直接调用 WebSocket 服务端 API
// 在 Laravel/Symfony 等框架中
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// 当有新通知时发布到 Redis 频道
$redis->publish('notification_channel', json_encode([
'user_id' => 123, => '新消息',
'content' => '有人评论了你的文章'
]));
同时在 WebSocket 服务端订阅该频道:
// 在 Workerman 进程初始化时
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->subscribe(['notification_channel'], function($redis, $channel, $msg) use ($ws_worker) {
$data = json_decode($msg, true);
if (isset($user_connections[$data['user_id']])) {
$user_connections[$data['user_id']]->send(json_encode([
'type' => 'notification',
'data' => $data
]));
}
});
SSE (Server-Sent Events)
适合单向推送(服务端→客户端),实现简单,原生 HTML5 支持。
实现步骤
创建 SSE 端点的 PHP 脚本
// sse.php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
$userId = $_GET['user_id']; // 实际应通过认证获取
while (true) {
// 从数据库/缓存获取最新通知
$notifications = getNewNotifications($userId);
if (!empty($notifications)) {
echo "data: " . json_encode($notifications) . "\n\n";
ob_flush();
flush();
}
sleep(2); // 轮询间隔
}
客户端 JS 代码
let eventSource = new EventSource('/sse.php?user_id=123');
eventSource.onmessage = function(event) {
let data = JSON.parse(event.data);
showNotification(data);
};
eventSource.onerror = function() {
console.error('SSE 连接断开');
};
缺点:PHP 脚本会长时间占用进程,高并发场景不推荐。
短轮询 + HTTP
适合对实时性要求不高的场景,实现最简单。
function pollNotifications() {
fetch('/api/notifications?last_id=0')
.then(res => res.json())
.then(data => {
if (data.length > 0) {
showNotifications(data);
}
});
setTimeout(pollNotifications, 5000); // 5秒轮询一次
}
第三方推送服务
对于企业级应用,直接使用成熟的推送服务:
| 服务 | 特点 | 适合场景 |
|---|---|---|
| Pusher | 原生 WebSocket,免费额度 | 快速原型、中小项目 |
| Firebase Cloud Messaging | 支持移动端和 Web | 跨平台通知 |
| Socket.IO | 需要搭配 Node.js | 复杂实时交互 |
| Mercure | 基于 SSE 的现代协议 | Symfony 生态推荐 |
长轮询 (Long Polling)
传统方案,在 PHP 中通过无限循环 + 超时实现:
set_time_limit(0);
$start = time();
while (time() - $start < 30) { // 最长等待30秒
$notifications = getNewNotifications($userId);
if (!empty($notifications)) {
echo json_encode($notifications);
exit;
}
usleep(500000); // 0.5秒检查一次
}
echo json_encode([]); // 超时返回空
综合推荐
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 高并发实时通讯 | WebSocket + Swoole/Workerman | 性能最优,双向通信 |
| 简单单向通知 | SSE | 实现简单,无需额外服务 |
| 快速原型/小项目 | Pusher/Firebase | 开箱即用,零运维 |
| 已有 Laravel 项目 | Laravel Echo + Pusher/Redis | 官方支持,集成度高 |
| 传统 PHP 项目 | 长轮询 | 纯 PHP 实现,无需扩展 |
实际项目最佳实践
以常见 Web 项目为例,推荐组合方案:
- WebSocket 服务器(Swoole/Workerman)
- Redis Pub/Sub 作为内部消息通道
- HTTP 业务代码发布通知到 Redis
- WebSocket 服务器订阅 Redis 并推送给用户
架构图:
[用户A] ←→ WebSocket服务器 ←→ Redis Pub/Sub ← PHP请求处理
[用户B] ←→ WebSocket服务器 ←→ Redis Pub/Sub ← 定时任务/其他系统
这样既保留了 PHP 的简易开发,又能获得实时推送能力,适合中大型项目。