WebSocket Protocol
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated detection is 'no' and the tools listed (reverb, soketi, ratchet, pusher) are WebSocket server libraries, not static analysis tools. Misuse patterns like long-polling instead of WebSockets, missing heartbeats, or unauthenticated upgrade handshakes are invisible to compilers and linters — they only surface through code review or runtime observation when connections silently drop or load balancers kill idle connections.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix suggests switching to Laravel Reverb or Soketi rather than rolling your own, which is a non-trivial change: it involves adding a WebSocket server process, updating client-side connection logic, adding authentication during the handshake, and wiring up reconnection/heartbeat logic. This spans multiple files and concerns but is contained within one system component rather than being fully cross-cutting.
Closest to 'persistent productivity tax' (b5). WebSocket infrastructure imposes ongoing operational weight: a persistent server process (not stateless HTTP), load balancer configuration for long-lived connections, heartbeat/ping management, reconnection logic on clients, and authentication at the handshake layer. Applies to web and API contexts per applies_to. Every developer touching real-time features must understand this model, but it doesn't define the entire system's shape.
Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field reveals a well-known trap: developers believe PHP cannot do WebSockets at all (standard PHP-FPM cannot, but Swoole/Ratchet/OpenSwoole can). Common mistakes reinforce additional traps — silent connection drops from missing heartbeats and unauthenticated upgrade handshakes are non-obvious. These are documented gotchas rather than catastrophic or architecture-contradicting surprises.
Also Known As
TL;DR
Explanation
WebSockets begin as an HTTP request with Upgrade: websocket header. After the server acknowledges, the connection upgrades to a persistent bidirectional TCP channel. Frames carry data in either direction — text or binary. Unlike HTTP request-response, the server can push data to the client at any time. The ws:// scheme is unencrypted; wss:// uses TLS. PHP WebSocket servers require a persistent process (Ratchet, Swoole, ReactPHP) since PHP-FPM terminates after each request.
Diagram
sequenceDiagram
participant C as Browser
participant S as Server
C->>S: HTTP GET /chat<br/>Upgrade: websocket
S-->>C: 101 Switching Protocols
Note over C,S: TCP connection kept open
C->>S: Frame: hello server
S-->>C: Frame: hello client
S-->>C: Frame: push notification
C->>S: Frame: ping
S-->>C: Frame: pong
C->>S: Frame: close
S-->>C: Frame: close
Note over C,S: Full duplex - both sides push any time
Common Misconception
Why It Matters
Common Mistakes
- Using WebSockets for request-response patterns — HTTP is more appropriate; WebSockets suit continuous bidirectional streams.
- No heartbeat/ping — idle WebSocket connections are silently dropped by load balancers; send periodic pings.
- No authentication on the WebSocket connection — validate a token during the upgrade handshake before accepting the connection.
- Not handling reconnection — connections drop; clients must implement exponential backoff reconnection logic.
Code Examples
// No authentication on WebSocket upgrade:
$server->on('open', function(ConnectionInterface $conn) {
$this->clients->attach($conn);
// Anyone who connects receives all messages — no auth check
});
// Authenticate during upgrade:
$server->on('open', function(ConnectionInterface $conn) {
$request = $conn->httpRequest;
$token = $request->getQueryParams()['token'] ?? '';
if (!$this->auth->validateToken($token)) {
$conn->close();
return;
}
$userId = $this->auth->getUserId($token);
$this->clients[$userId] = $conn;
});