PHP项目中如何实现消息推送?

wen PHP项目 4

本文目录导读:

PHP项目中如何实现消息推送?

  1. 方案一:Server-Sent Events (SSE) — 轻量级,单向推送
  2. 方案二:WebSocket — 双向实时通信
  3. 方案三:轮询 (Polling) — 简单但低效
  4. 方案四:长轮询 (Long Polling) — 兼容性好,延迟较低
  5. 方案五:第三方推送服务 — 省时省力
  6. 总结建议

在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 和长轮询会占用进程),如果并发需求高,建议使用 SwooleWorkerman 这类常驻内存的框架。

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