WebSockets в PHP: Создаём real-time приложения без магии

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Веб-сокеты в PHP: как заставить сайт говорить в реальном времени

Представьте себе обычный сайт. Вы нажали кнопку — и ждёте, пока обновится страница. Это как отправлять письмо почтой: выбросил в ящик и надеешься, что дойдёт. А теперь представьте, что вы общаетесь по телефону — сразу слышите собеседника. WebSockets — это именно такой «телефон» для веба. И да, на PHP это работает.

Многие считают, что WebSocket — это удел Node.js или Python. Но PHP, хоть и был создан для «склеивания» HTML, давно перерос свою колыбель. Сегодня мы разберём, как сделать real-time приложение на PHP — будь то чат, лента уведомлений или живая аналитика. И никаких костылей.

Если вы когда-нибудь пытались сделать live чат на PHP через long polling и видели, как сервер падает под 1000 запросов в секунду — эта статья для вас. WebSockets меняют правила игры.

Что такое WebSocket и почему PHP с ним дружит?

WebSocket — это двусторонний канал связи между браузером и сервером. В отличие от HTTP, где клиент всегда инициирует запрос, здесь сервер может сам отправить данные клиенту. Это даёт настоящее реальное время, а не его имитацию.

Ключевое отличие от long polling (когда клиент постоянно спрашивает «ну что, есть новости?») — в WebSocket соединение держится открытым. Один раз установили — и общаетесь без перерыва. Экономия трафика и ресурсов колоссальная.

PHP, как язык, выполняет скрипты последовательно. Но это не мешает ему быть отличным сервером для WebSocket. Секрет в архитектуре: мы не запускаем PHP через веб-сервер (Apache/Nginx) для каждого соединения, а используем его как самостоятельный демон. И тут на сцену выходят библиотеки.

Библиотеки для WebSocket на PHP: что выбрать?

Самых популярных библиотек две — и обе заслуживают внимания:

  • Ratchet — дедушка PHP WebSocket. Надёжный, проверенный, но немного «старорежимный». Использует событийную модель на основе ReactPHP. Отлично подходит для простых чатов и уведомлений.
  • Swoole — зверь. Это не просто библиотека, а целый движок, который переписывает ядро PHP. Даёт асинхронность, корутины и производительность, близкую к Go. Но требует установки расширения на сервере.

Для первого знакомства я рекомендую Ratchet — он проще в освоении и не требует правки php.ini. Плюс, он прекрасно работает в связке с ReactPHP, который мы тоже сегодня затронем.

Пишем простой WebSocket-сервер на PHP с Ratchet

Давайте создадим базовый эхо-сервер. Он будет принимать сообщения от клиента и отправлять их обратно. Это классический «Hello, World» для WebSocket.

Сначала установим Ratchet через Composer. Откройте терминал в корне проекта:

composer require cboden/ratchet

Теперь создадим файл server.php:

<?php
require __DIR__ . '/vendor/autoload.php';

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class EchoServer implements MessageComponentInterface {
    public function onOpen(ConnectionInterface $conn) {
        echo "Новое соединение: {$conn->resourceId}\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        echo "Получено: {$msg}\n";
        $from->send("Эхо: {$msg}");
    }

    public function onClose(ConnectionInterface $conn) {
        echo "Соединение {$conn->resourceId} закрыто\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "Ошибка: {$e->getMessage()}\n";
        $conn->close();
    }
}

// Запускаем сервер
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;

$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new EchoServer()
        )
    ),
    8080
);

echo "WebSocket сервер запущен на порту 8080...\n";
$server->run();

Запустите сервер командой:

php server.php

Теперь откройте консоль браузера (F12) и введите:

let ws = new WebSocket('ws://localhost:8080');
ws.onmessage = e => console.log(e.data);
ws.send('Привет, WebSocket!');

Вы увидите в консоли: Эхо: Привет, WebSocket!. Поздравляю — вы только что сделали real-time приложение на PHP!

Сложный пример: чат-комната с историей

Давайте усложним задачу. Сделаем live чат на PHP, где все видят сообщения друг друга, а новые участники получают историю последних 10 сообщений.

Создадим новый класс ChatServer.php:

<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class ChatServer implements MessageComponentInterface {
    protected $clients;
    protected $history = [];

    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
        echo "Новый пользователь. Всего: {$this->clients->count()}\n";

        // Отправляем историю новому участнику
        $history = array_slice($this->history, -10);
        if (!empty($history)) {
            $conn->send(json_encode([
                'type' => 'history',
                'messages' => $history
            ]));
        }

        // Уведомляем всех о новом участнике
        $this->broadcast(json_encode([
            'type' => 'system',
            'message' => 'Пользователь #' . $conn->resourceId . ' присоединился'
        ]), $conn);
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $data = json_decode($msg, true);
        if (!$data || !isset($data['message'])) return;

        $message = [
            'type' => 'message',
            'user' => 'Пользователь #' . $from->resourceId,
            'text' => htmlspecialchars($data['message']),
            'time' => date('H:i:s')
        ];

        // Сохраняем в истории
        $this->history[] = $message;

        // Отправляем всем
        $this->broadcast(json_encode($message), $from);
    }

    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
        $this->broadcast(json_encode([
            'type' => 'system',
            'message' => 'Пользователь #' . $                

Блоги

Рекомендаций по книгам