PHPackages                             ez-php/broadcast - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. ez-php/broadcast

ActiveLibrary[Framework](/categories/framework)

ez-php/broadcast
================

Real-time event broadcasting for ez-php — pluggable drivers (Null, Log, Array), SSE response helpers, and a static Broadcast facade

1.0.1(1mo ago)00MITPHPPHP ^8.5CI passing

Since Mar 23Pushed 1mo agoCompare

[ Source](https://github.com/ez-php/broadcast)[ Packagist](https://packagist.org/packages/ez-php/broadcast)[ Docs](https://github.com/ez-php/broadcast)[ RSS](/packages/ez-php-broadcast/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (8)Versions (6)Used By (0)

ez-php/broadcast
================

[](#ez-phpbroadcast)

Real-time event broadcasting for ez-php applications. Publish events to named channels via a pluggable driver (Null, Log, Array) and stream them to connected clients using Server-Sent Events (SSE).

---

Installation
------------

[](#installation)

```
composer require ez-php/broadcast
```

---

Quick Start
-----------

[](#quick-start)

Register the provider in `provider/modules.php`:

```
use EzPhp\Broadcast\BroadcastServiceProvider;

$app->register(BroadcastServiceProvider::class);
```

Add configuration to `config/broadcast.php`:

```
return [
    'driver'   => env('BROADCAST_DRIVER', 'null'),
    'log_path' => env('BROADCAST_LOG_PATH', ''),
];
```

Publish an event from anywhere:

```
use EzPhp\Broadcast\Broadcast;

Broadcast::to('notifications', 'UserCreated', ['id' => 42, 'name' => 'Alice']);
```

---

Broadcastable Events
--------------------

[](#broadcastable-events)

Implement `BroadcastableInterface` to make any event class broadcastable:

```
use EzPhp\Broadcast\BroadcastableInterface;

class UserCreated implements BroadcastableInterface
{
    public function __construct(private readonly int $userId) {}

    public function broadcastOn(): string
    {
        return 'notifications';
    }

    public function broadcastAs(): string
    {
        return 'UserCreated';
    }

    public function broadcastWith(): array
    {
        return ['id' => $this->userId];
    }
}
```

Dispatch via the facade:

```
Broadcast::event(new UserCreated(42));
```

---

Drivers
-------

[](#drivers)

Driver`BROADCAST_DRIVER`DescriptionNull`null`Silently discards all events (default)Log`log`Writes a summary to a log file or via `error_log()`Array`array`Stores events in memory — designed for testing### Log Driver

[](#log-driver)

```
BROADCAST_DRIVER=log
BROADCAST_LOG_PATH=/var/www/html/storage/logs/broadcast.log
```

When `BROADCAST_LOG_PATH` is empty, events are written via `error_log()`.

### Array Driver (for Testing)

[](#array-driver-for-testing)

```
use EzPhp\Broadcast\Broadcast;
use EzPhp\Broadcast\Broadcaster;
use EzPhp\Broadcast\Driver\ArrayDriver;

$driver = new ArrayDriver();
Broadcast::setBroadcaster(new Broadcaster($driver));

// ... exercise code under test ...

$events = $driver->eventsOn('notifications');
assert(count($events) === 1);
assert($events[0]['event'] === 'UserCreated');

Broadcast::resetBroadcaster();
```

---

Server-Sent Events (SSE)
------------------------

[](#server-sent-events-sse)

`SseEvent` and `SseStream` provide the building blocks for SSE endpoints.

### SseEvent

[](#sseevent)

A single SSE frame (RFC 8895):

```
use EzPhp\Broadcast\Sse\SseEvent;

$frame = new SseEvent(
    data:  json_encode(['id' => 42]),
    event: 'UserCreated',     // optional event type
    id:    'msg-1',           // optional ID for reconnection
    retry: 3000,              // optional reconnect interval (ms)
);

echo $frame->toString();
// id: msg-1
// event: UserCreated
// retry: 3000
// data: {"id":42}
//
```

Multi-line data is handled automatically — each newline in `$data` produces a separate `data:` line.

### SseStream

[](#ssestream)

Wraps an iterable of `SseEvent` objects and provides the correct HTTP headers:

```
use EzPhp\Broadcast\Sse\SseEvent;
use EzPhp\Broadcast\Sse\SseStream;

// In a controller:
public function stream(): void
{
    $events = $this->generateEvents(); // returns Generator

    $stream = new SseStream($events);

    foreach ($stream->getHeaders() as $name => $value) {
        header("$name: $value");
    }

    $stream->stream(function (string $chunk): void {
        echo $chunk;
        ob_flush();
        flush();
    });
}
```

**Headers set by `getHeaders()`:**

HeaderValue`Content-Type``text/event-stream``Cache-Control``no-cache``Connection``keep-alive``X-Accel-Buffering``no` *(disables nginx buffering)*---

Static Facade
-------------

[](#static-facade)

`Broadcast` is a static facade backed by a `Broadcaster` singleton:

MethodDescription`Broadcast::event(BroadcastableInterface)`Publish via `broadcastOn()`, `broadcastAs()`, `broadcastWith()``Broadcast::to(string $channel, string $event, array $payload)`Publish directly`Broadcast::setBroadcaster(Broadcaster)`Wire the singleton (done by `BroadcastServiceProvider`)`Broadcast::resetBroadcaster()`Reset to null — call in test `tearDown()`Throws `RuntimeException` if called before `setBroadcaster()`.

---

Custom Driver
-------------

[](#custom-driver)

Implement `BroadcastDriverInterface` to add a custom backend:

```
use EzPhp\Broadcast\BroadcastDriverInterface;

final class RedisPubSubDriver implements BroadcastDriverInterface
{
    public function __construct(private readonly \Redis $redis) {}

    public function publish(string $channel, string $event, array $payload): void
    {
        $this->redis->publish($channel, json_encode([
            'event'   => $event,
            'payload' => $payload,
        ]));
    }
}
```

Bind it in a service provider:

```
$app->bind(BroadcastDriverInterface::class, fn () => new RedisPubSubDriver($redis));
```

---

Client-Side Usage (JavaScript)
------------------------------

[](#client-side-usage-javascript)

The browser's built-in `EventSource` API consumes SSE streams with no extra library required.

### Basic subscription

[](#basic-subscription)

```
const events = new EventSource('/events/notifications');

// Listen for a named event (matches the `event:` field in the SSE frame)
events.addEventListener('UserCreated', (e) => {
    const payload = JSON.parse(e.data);
    console.log('New user:', payload.id, payload.name);
});

// Listen for unnamed messages (only `data:` field, no `event:` field)
events.onmessage = (e) => {
    console.log('Message:', e.data);
};

// Handle connection errors and reconnection
events.onerror = (err) => {
    console.error('SSE error', err);
    // EventSource reconnects automatically after the `retry:` interval (default 3 s)
};

// Close the stream when no longer needed
// events.close();
```

### Authenticated streams

[](#authenticated-streams)

SSE uses standard HTTP — pass credentials via a cookie or a query-parameter token (headers are not configurable in the browser `EventSource` API):

```
const token = document.querySelector('meta[name="api-token"]').content;
const events = new EventSource(`/events/notifications?token=${token}`);
```

On the PHP side, validate `$_GET['token']` in the SSE controller before opening the stream.

### Multiple event types on one connection

[](#multiple-event-types-on-one-connection)

```
const events = new EventSource('/events/feed');

['OrderPlaced', 'OrderShipped', 'OrderDelivered'].forEach((type) => {
    events.addEventListener(type, (e) => {
        const order = JSON.parse(e.data);
        updateOrderUI(order);
    });
});
```

---

Exceptions
----------

[](#exceptions)

`BroadcastException` (extends `RuntimeException`) is the base exception for this package. `Broadcast::event()` / `Broadcast::to()` throw `RuntimeException` if called before the broadcaster is set.

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance91

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 87.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

5

Last Release

46d ago

Major Versions

0.9.3 → 1.0.02026-03-24

### Community

Maintainers

![](https://www.gravatar.com/avatar/a15a63c46d239d42b8ed4c2fe9adbc5fe99eb62f6e5bb90f08021e0c068e8b37?d=identicon)[AU9500](/maintainers/AU9500)

---

Top Contributors

[![AU9500](https://avatars.githubusercontent.com/u/122030400?v=4)](https://github.com/AU9500 "AU9500 (36 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (5 commits)")

---

Tags

phpframeworksseBroadcastserver sent eventsez-php

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ez-php-broadcast/health.svg)

```
[![Health](https://phpackages.com/badges/ez-php-broadcast/health.svg)](https://phpackages.com/packages/ez-php-broadcast)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
