Skip to main content
WebSockets Tutorial
CHAPTER 18 Beginner

Building WebSocket Servers with PHP

Updated: May 14, 2026
30 min read

# CHAPTER 18

Building WebSocket Servers with PHP

1. Introduction

Throughout this tutorial, we have focused heavily on the Client (JavaScript). But a WebSocket connection requires a robust backend Server to accept the handshakes, hold the connections open, and route the messages. While Node.js is famous for WebSockets, PHP is fully capable of running high-performance WebSocket servers! In this chapter, we will look at how PHP achieves this using Event Loops and the popular Ratchet library.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand why traditional PHP (LAMP stack) struggles with WebSockets.
  • Explain the concept of an Event Loop (ReactPHP/Swoole).
  • Identify the components of the Ratchet library.
  • Write a basic CLI-based PHP WebSocket server.

3. Beginner-Friendly Explanation

  • Traditional PHP: A customer walks into a fast-food restaurant, places an order, gets their food, and leaves immediately. The cashier (PHP) forgets about them.
  • WebSocket PHP: You need a bartender. The customer sits at the bar, orders a drink, and stays there for 3 hours, occasionally ordering more.
Traditional PHP scripts are designed to "die" the moment they finish sending a webpage. To make PHP hold connections open for hours, we have to run PHP from the command line (CLI) as a continuous, never-ending loop (an Event Loop).

4. Real-World Examples

  • Ratchet: A highly popular PHP library based on ReactPHP. It is perfect for standard applications and works natively on any PHP setup.
  • Swoole / OpenSwoole: A C-extension for PHP that runs at blazing speeds. Used by enterprise companies to handle millions of connections in PHP.

5. Step-by-Step Tutorial

Let's look at how to build a server using Ratchet.

Step 1: Install Ratchet via Composer (composer require cboden/ratchet). Step 2: Create a PHP class that implements MessageComponentInterface. Step 3: Implement four required methods: onOpen, onMessage, onClose, onError. Step 4: Create a script (server.php) to instantiate the server and run it via the command line.

6. The Ratchet Chat Class

Here is the core logic. Notice how closely it maps to the JavaScript events we learned earlier!

7. PHP Ratchet Example

php
1234567891011121314151617181920212223242526272829303132333435363738394041424344
<?php
namespace MyApp;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
        // SplObjectStorage is an array specifically designed to hold Objects safely
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients->attach($conn);
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $numRecv = count($this->clients) - 1;
        echo sprintf(&#039;Connection %d sending message "%s" to %d other connection%s' . "\n",
            $from->resourceId, $msg, $numRecv, $numRecv == 1 ? &#039;' : 's');

        // BROADCASTING: Send to everyone EXCEPT the sender
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn) {
        // The connection is closed, remove it from our list
        $this->clients->detach($conn);
        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";
        $conn->close();
    }
}

8. Running the Server

You don't run this code through Apache or Nginx by visiting a URL. You create a bootstrapper script (server.php):
php
1234567891011121314151617181920
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;

require dirname(__DIR__) . &#039;/vendor/autoload.php';

// Wrap our Chat logic inside WebSocket and HTTP handlers
$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new Chat()
        )
    ),
    8080 // Port number
);

echo "Server running on port 8080...\n";
$server->run();

To start the server, open your terminal and run: php server.php The terminal will hang indefinitely, listening for connections. Your server is alive!

9. Why SplObjectStorage?

In PHP, using a standard array ($clients[] = $conn) can cause memory leaks when dealing with objects. SplObjectStorage is a specialized structure built into PHP that manages object references perfectly, preventing your long-running server from consuming all your RAM.

10. Best Practices

  • Supervisord: Because the server runs in the terminal, if it crashes, it stops working permanently. In production, use a tool like "Supervisor" (on Linux) to monitor the script and automatically restart it if it fails.
  • Do not block the loop: If you run a slow MySQL query (sleep(5)) inside onMessage, it will freeze the server for 5 seconds. NO ONE else will be able to send messages during that time. Use Async queries or offload heavy work.

11. Common Mistakes

  • Putting the server in cPanel: Standard shared hosting (cPanel/Apache) aggressively kills any PHP script that runs for longer than 30-120 seconds. You need a VPS (Virtual Private Server) like DigitalOcean, Linode, or AWS with terminal access to run a persistent WebSocket daemon.

12. Mini Exercises

  1. 1. Look at the onMessage loop in Section 7. Notice the if ($from !== $client). This is the exact broadcasting logic we studied in Chapter 9!

13. Coding Challenges

Challenge 1: Modify the Ratchet onOpen method. Whenever a new user connects, use a foreach loop to send a message to all *existing* clients saying "A new user has joined the room!"

14. MCQs with Answers

Question 1

How do you execute a PHP WebSocket server?

Question 2

What is the primary risk of running heavy, synchronous tasks (like downloading a large file) inside the Ratchet onMessage method?

15. Interview Questions

  • Q: Explain why traditional Apache/PHP-FPM architecture is fundamentally unsuited for hosting WebSockets.
  • Q: What is the purpose of SplObjectStorage in Ratchet?

16. FAQs

Q: Can I use Laravel for WebSockets? A: Yes! The Laravel ecosystem provides Laravel WebSockets (a Ratchet wrapper) and Laravel Reverb (a highly optimized native WebSocket server). They make integrating WebSockets with your database and authentication seamless.

17. Summary

In Chapter 18, we broke the rules of traditional PHP. By running our scripts from the terminal and utilizing libraries like Ratchet and ReactPHP, we created a long-running daemon capable of accepting WebSocket handshakes, managing an array of connections, and broadcasting messages synchronously.

18. Next Chapter Recommendation

We have all the pieces: the UI, the client logic, the protocol theory, and the backend server. Proceed to Chapter 19: Building a Complete Real-Time Project to wire everything together into a masterpiece!

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·