Broadcasting
Broadcasting is how php-via pushes updates to multiple clients at once. When a user's action should change what everyone sees — not just themselves — you broadcast to a scope.
The basics
Call $app->broadcast(scope) after modifying shared state. Every context registered
in that scope will re-render its view and push the update via SSE:
$increment = $c->action(function (Context $c) use ($app, $counter): void {
$newVal = $app->globalState('shared_counter') + 1;
$app->setGlobalState('shared_counter', $newVal);
$counter->setValue($newVal);
// Push to everyone on this route
$app->broadcast(Scope::routeScope('/'));
}, 'increment');
Scope targets
You can broadcast to any scope string:
// All connected clients everywhere
$app->broadcast(Scope::GLOBAL);
// All clients on a specific route
$app->broadcast(Scope::routeScope('/dashboard'));
// A custom scope (e.g. a chat room)
$app->broadcast('room:lobby');
// Equivalent shorthand when inside a context:
$c->broadcast(); // broadcasts to $c's primary scope
Auto-broadcast on scoped signals
Scoped signals auto-broadcast when setValue() is called — you don't always need
an explicit broadcast(). The auto-broadcast fires to the signal's scope:
// This signal is ROUTE-scoped. Calling setValue() auto-broadcasts to route:/
$shared = $c->signal($app->globalState('count'), 'count', Scope::routeScope('/'));
$c->action(function (Context $c) use ($app, $shared): void {
$shared->setValue($app->globalState('count') + 1);
// No explicit broadcast needed — auto-broadcast fires for Scope::routeScope('/')
}, 'inc');
Broadcasting on connect and disconnect
Use onClientConnect / onClientDisconnect app-level hooks to broadcast
whenever a client joins or leaves. This replaces polling timers for presence features:
// Broadcast to the route when occupancy changes — presence counter stays live
$app->onClientConnect(fn(Context $c) => $app->broadcast(Scope::routeScope($c->getRoute())));
$app->onClientDisconnect(fn(Context $c) => $app->broadcast(Scope::routeScope($c->getRoute()))); See Lifecycle for full details on connect/disconnect hooks.
Combining global state and broadcast
Use setGlobalState to store shared data in process memory, then broadcast to re-render
all clients with the new value. The standard multiplayer pattern:
// Initialize once
$app->setGlobalState('messages', []);
// In an action:
$send = $c->action(function (Context $c) use ($app): void {
$msgs = $app->globalState('messages');
$msgs[] = ['user' => substr($c->getId(), -4), 'text' => $_POST['text'] ?? ''];
$app->setGlobalState('messages', array_slice($msgs, -50)); // keep last 50
$app->broadcast(Scope::routeScope('/chat'));
}, 'send');
Next steps
- Scopes — understanding scope types and targets
- Lifecycle — connect/disconnect hooks and timers
- Actions — server-side handlers that trigger broadcasts
- API: broadcast() — method signature