PHP项目如何实现实时通知功能?

wen PHP项目 4

本文目录导读:

PHP项目如何实现实时通知功能?

  1. 方案一:WebSocket(推荐)
  2. 方案二:SSE (Server-Sent Events)
  3. 方案三:短轮询 + HTTP
  4. 方案四:第三方推送服务
  5. 方案五:长轮询 (Long Polling)
  6. 综合推荐
  7. 实际项目最佳实践

在 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 项目为例,推荐组合方案:

  1. WebSocket 服务器(Swoole/Workerman)
  2. Redis Pub/Sub 作为内部消息通道
  3. HTTP 业务代码发布通知到 Redis
  4. WebSocket 服务器订阅 Redis 并推送给用户

架构图:

[用户A] ←→ WebSocket服务器 ←→ Redis Pub/Sub ← PHP请求处理
[用户B] ←→ WebSocket服务器 ←→ Redis Pub/Sub ← 定时任务/其他系统

这样既保留了 PHP 的简易开发,又能获得实时推送能力,适合中大型项目。

抱歉,评论功能暂时关闭!