-
Notifications
You must be signed in to change notification settings - Fork 0
Recipe Broadcast
broadcast() is the package's fan-out primitive. The same method covers three patterns; the right one is selected by the type of the second argument.
public function broadcast(
string $message,
int|string|array|null $clients = null,
): bool;$clients |
Reach |
|---|---|
null |
Every alive client. |
| `int | string` |
| `array<int | string>` |
Return value: true if the dispatch completed (even when zero clients matched). false only if something in the loop raised — which the package internally swallows to keep live() resilient.
$server->live(function ($srv, $conn) {
$payload = $conn->read();
if ($payload !== null) {
$srv->broadcast($payload); // everyone sees the bytes the sender posted
}
});isAlive() is checked per recipient before write(). Dead connections in the registry are skipped silently and evicted on the next loop iteration.
$server->live(function ($srv, $conn) {
$line = trim((string) $conn->read());
if (preg_match('/^TO\s+(\S+)\s+(.+)$/', $line, $m)) {
$srv->broadcast($m[2], $m[1]); // single id
}
});If $m[1] is not mapped (nobody registered with that name), the call is a no-op.
$srv->broadcast("⚠ maintenance window starts in 10 min", ['admin', 'oncall', 'sre']);The package iterates the list, looks each id up in clientIdMap, and writes to each match. Unknown ids cost nothing.
For anything not covered by the three modes — sending to clients filtered by an arbitrary predicate, for example — use getClients() directly:
$server->live(function ($srv, $conn) {
if ($conn->read() !== 'hello vips') {
return;
}
foreach ($srv->getClients() as $id => $other) {
if (is_string($id) && str_starts_with($id, 'vip-')) {
$other->write("hi VIP {$id}\n");
}
}
});getClients() returns a map keyed by registered id (string) or the server's internal numeric key for clients that never registered. See Connection and Channel for the identity contract.
UDP has the same broadcast() shape but with caveats:
- A peer is "known" only after speaking once — there is no discovery.
- Each
write()is a separatesocket_sendto; the kernel may drop any one of them. -
isAlive()on a UDP connection is application-level — the server keeps writing to peers it has not heard from until youclose()them.
$server = Socket::server(Transport::UDP, '0.0.0.0', 9000);
$server->listen();
$server->live(function ($srv, $conn) {
$payload = $conn->read(65535);
if ($payload === 'ANNOUNCE') {
$srv->broadcast('hello room', null);
}
});- Order — clients receive messages in the order they were registered. There is no priority queue.
-
Atomicity — broadcast is per-recipient
write(). If the OS buffers fill mid-loop, that recipient's write may be short or fail; others continue. -
Error handling —
broadcast()catchesThrowableand returnsfalse. The wrap exists so a misbehaving channel cannot kill the loop. Inspect the return value when you care.
- Recipe Chat Server — broadcast in a richer protocol context.
-
Server Lifecycle — when
broadcast()is a no-op (beforelisten(), afterclose()). -
Connection and Channel — identity and the
clientIdMap.
initphp/socket · MIT · PHP 8.1+ · part of the InitPHP family · file issues at InitPHP/Socket/issues
Getting started
Transports
Concepts
Reference
Recipes
Operational