-
Notifications
You must be signed in to change notification settings - Fork 2
EventEmitter
InitPHP\Events\EventEmitter is the low-level, instantiable side of the
package. It implements
EventEmitterInterface and
exposes a Node.js-style API: on, once, emit, removeListener,
removeAllListeners, listeners, clearOnceListeners.
use InitPHP\Events\EventEmitter;
$emitter = new EventEmitter();
$emitter->on('hello', function ($name) {
echo "Hello {$name}!\n";
});
$emitter->emit('hello', ['World']); // → Hello World!Reach for EventEmitter when:
- You want a plain object you can inject and pass around.
- You need
once()— one-shot listeners that auto-detach after firing. - You need to remove a specific listener (
removeListener) or flush all listeners (removeAllListeners). - You want fluent chaining —
on()/once()return$this.
If you would rather call the same registry statically from anywhere, use
the Events facade.
namespace InitPHP\Events;
class EventEmitter implements EventEmitterInterface
{
public function on(string $event, callable $listener, int $priority = 100): self;
public function once(string $event, callable $listener, int $priority = 100): self;
public function emit(string $event, array $arguments = []): void;
public function removeListener(string $event, callable $listener): void;
public function removeAllListeners(?string $event = null): void;
public function clearOnceListeners(?string $event = null): void;
public function listeners(?string $event = null): array;
}Registers a listener for $event. Fluent — returns $this so you can
chain calls.
$emitter
->on('order.placed', $auditLog)
->on('order.placed', $sendEmail)
->on('order.placed', $awardPoints);-
$eventis case-insensitive (lowercased internally). -
$listenercan be any PHP callable. -
$priorityis an integer. Lower values run first. The named constants live onEvent(PRIORITY_HIGH = 10,PRIORITY_NORMAL = 100,PRIORITY_LOW = 200) but you can pass the integers directly. See Listeners & Priorities for the full ordering contract.
Throws \InvalidArgumentException if $event is not a string,
$listener is not callable, or $priority is not an integer.
Registers a one-shot listener: it fires the next time the event is emitted, then is automatically detached.
$emitter->once('payment.captured', function ($amount) {
echo "first capture: {$amount}\n";
});
$emitter->emit('payment.captured', [100]); // → first capture: 100
$emitter->emit('payment.captured', [200]); // → (silence — once fires once)Same validation as on(). The listener is queued alongside regular
listeners and is fired in the same iteration as them.
Detachment semantic. All
oncelisteners for an event name are cleared as a group on the firstemit($name), regardless of how many you registered. If youoncetwo listeners for the same event, both fire on the first emit, then both are gone. If a listener throws the cleanup does not run (the exception propagates out ofemitimmediately); callclearOnceListeners($event)yourself if you need the "fire at most once even on exceptions" contract.
Invokes every listener registered for $event (both on and once),
in ascending priority order, passing $arguments straight through.
$emitter->on('greet', function ($name, $greeting) {
echo "{$greeting}, {$name}!\n";
});
$emitter->emit('greet', ['World', 'Hello']);
// → Hello, World!-
Arguments are passed as an array, not as varargs. The array is
unpacked positionally by
call_user_func_array, so the listener signature simply lists the arguments in order. - Listeners fire in priority order. Lower numeric priority runs first; within the same priority, registration order (FIFO). See Listeners & Priorities.
-
Return value is
void. UnlikeEvents::trigger(),EventEmitter::emit()ignores whatever listeners return — there is no short-circuit onfalse. -
One-shot listeners are dropped after the call. This is the only
cleanup
emit()performs. If you need to drop one-shots without firing them first, callclearOnceListeners(). - If
$eventis not a string or$argumentsis not an array,\InvalidArgumentExceptionis thrown.
Heads-up for upgraders. The 1.x line of the standalone
initphp/event-emitterpackage had a bug inemit()that silently ran no listeners. That is fixed ininitphp/events:^2.0. If your 1.x code hademit()calls that quietly never invoked anything, they will now actually fire — see Migration Guide.
Detaches the exact listener instance previously registered for that
event (across both on and once queues). Strict comparison (===) is
used, so you must hand back the same callable reference you registered.
$auditLog = function ($order) { /* … */ };
$emitter->on('order.placed', $auditLog);
// …later…
$emitter->removeListener('order.placed', $auditLog);If the listener is not found, the call is a no-op. Throws on invalid argument types.
Closures are identity-compared. Two anonymous functions with the same body are not equal — you must keep a reference to the closure you registered if you ever intend to remove it. Plain function names (
'my_func') and[$obj, 'method']pairs are easier to pass around.
With an event name, removes every listener (both on and once) for
that one event. With null, wipes the entire registry.
$emitter->removeAllListeners('order.placed'); // only this event
$emitter->removeAllListeners(); // everythingUseful between test cases, or when you tear down a subsystem and want to ensure no stale handlers survive.
Drops one-shot listeners without invoking them. With an event name,
clears only that event's once-listeners; with null, clears every
one-shot listener across every event. Regular on() listeners are
never touched.
$emitter->once('boot', $listener);
$emitter->clearOnceListeners('boot'); // dropped without firingThis is mostly used internally by higher-level dispatchers (the
Events facade's trigger() uses it in a try/finally
block to honour the once-contract even when the chain is halted by a
false return). Application code rarely needs it directly.
Throws \InvalidArgumentException if $event is provided but is not
a string.
Returns the listeners currently registered for $event, already merged
across both the regular and one-shot registries and sorted by
priority (lower numeric value first; FIFO within a priority bucket).
-
listeners('user.registered')→ listeners for that one event. -
listeners()(no argument) → listeners for every registered event, concatenated into one array.
foreach ($emitter->listeners('user.registered') as $callable) {
// each $callable is exactly the value you registered;
// iteration order matches the order emit() would invoke them.
}The returned array is a snapshot; mutating it does not affect the registry.
// EventEmitter — arguments as an array
$emitter->emit('user.registered', [$user, 'web']);
// Events facade — arguments as varargs
Events::trigger('user.registered', $user, 'web');Listeners always receive the unpacked positional arguments, so the listener signature is identical in either case:
function (array $user, string $source) { /* … */ }<?php
require __DIR__ . '/vendor/autoload.php';
use InitPHP\Events\EventEmitter;
$bus = new EventEmitter();
$logger = function (array $order) {
echo "log: order {$order['id']}\n";
};
$bus
->on('order.placed', $logger)
->on('order.placed', function (array $order) {
echo "mail: {$order['email']}\n";
})
->once('order.placed', function (array $order) {
echo "first-ever order welcomed: {$order['email']}\n";
});
$bus->emit('order.placed', [['id' => 1, 'email' => 'a@x']]);
$bus->emit('order.placed', [['id' => 2, 'email' => 'b@x']]);
// Drop the audit logger for the third call.
$bus->removeListener('order.placed', $logger);
$bus->emit('order.placed', [['id' => 3, 'email' => 'c@x']]);Output:
log: order 1
mail: a@x
first-ever order welcomed: a@x
log: order 2
mail: b@x
mail: c@x
-
Eventsfacade — the static, app-wide flavour of the same engine. - Listeners & Priorities — what counts as a listener and how ordering really works.
-
Migration Guide — coming from
initphp/event-emitter. - API Reference — the full method matrix.
initphp/events · MIT License · part of the InitPHP family
Source · Issues · Discussions · Packagist · Contributing · Security Policy
Getting Started
Core APIs
Practical
Reference