Documentation menu

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