Skip to content

Quick Start

Muhammet Şafak edited this page May 25, 2026 · 2 revisions

Quick Start

This page takes you from a fresh composer require to firing your first event in under five minutes. If you have not installed yet, start at Installation.

Choose your API

The package ships two APIs that share the same underlying engine. Pick whichever fits how you want to structure your code.

You want… Use…
One global registry, used statically from anywhere Events facade
A plain object you can construct, inject, and pass around EventEmitter
Stop a chain mid-way by returning false Events facade
Simulate / debug instrumentation Events facade
Plain emit() with no short-circuit, no global state EventEmitter

Both APIs support once() (one-shot listeners), off() / removeListener() (remove a specific listener), and removeAllListeners() (wipe one event or every event). Pick the API based on the first three rows of the table; the lifecycle controls are on both.

You can use both side-by-side in the same project; they do not share a listener registry, which is by design.

Three-line example — Events facade

<?php
require __DIR__ . '/vendor/autoload.php';

use InitPHP\Events\Events;

Events::on('app.boot', function () {
    echo "App is up\n";
});

Events::trigger('app.boot');
$ php boot.php
App is up

That is the entire programming model: register listeners with Events::on($name, $callback), fire them with Events::trigger($name, ...$args).

Three-line example — EventEmitter

<?php
require __DIR__ . '/vendor/autoload.php';

use InitPHP\Events\EventEmitter;

$emitter = new EventEmitter();

$emitter->on('hello', function ($name) {
    echo "Hello {$name}!\n";
});

$emitter->emit('hello', ['World']);
$ php hello.php
Hello World!

Note the argument-passing convention:

  • Events::trigger($name, ...$args) accepts variadic arguments.
  • EventEmitter::emit($name, array $args) accepts arguments as an array.

This difference is intentional — see Events Facade and EventEmitter for the rationale.

Passing arguments

Any number of arguments can flow from the trigger site to every listener:

use InitPHP\Events\Events;

Events::on('user.registered', function (array $user, string $source) {
    echo "User {$user['email']} signed up via {$source}\n";
});

Events::trigger('user.registered', ['email' => 'jane@example.com'], 'web');
User jane@example.com signed up via web

The same flow via EventEmitter:

$emitter->on('user.registered', function (array $user, string $source) { /* … */ });
$emitter->emit('user.registered', [['email' => 'jane@example.com'], 'web']);

Multiple listeners on one event

You can attach as many listeners to a name as you like. By default they share the same priority (PRIORITY_NORMAL = 100) and fire in registration order within that bucket:

use InitPHP\Events\Events;

Events::on('order.placed', function ($order) { echo "log: {$order['id']}\n"; });
Events::on('order.placed', function ($order) { echo "mail: {$order['email']}\n"; });
Events::on('order.placed', function ($order) { echo "queue: {$order['id']}\n"; });

Events::trigger('order.placed', ['id' => 42, 'email' => 'jane@x']);
log: 42
mail: jane@x
queue: 42

Pass an explicit priority to override the order. Lower numeric value runs first, regardless of when each listener was registered:

Events::on('order.placed', fn () => print("late\n"),  Events::PRIORITY_LOW);   // 200
Events::on('order.placed', fn () => print("first\n"), Events::PRIORITY_HIGH);  // 10
Events::trigger('order.placed', ['id' => 42]);
// → first
// → late

Full ordering contract: Listeners & Priorities.

Stopping the chain

Return false from any listener and the remaining listeners for that event are skipped. trigger() returns false in that case, otherwise true.

Events::on('save', function () { return false; }); // veto
Events::on('save', function () { echo "never runs\n"; });

if (Events::trigger('save') === false) {
    echo "A listener vetoed the operation.\n";
}

Details and patterns: Stopping Propagation.

One-shot listeners

Both APIs expose once() — the listener fires at most once and is discarded after the next dispatch (even if the chain was stopped by a false return, or a listener threw).

use InitPHP\Events\Events;

Events::once('payment.captured', function ($amount) {
    echo "first capture: {$amount}\n";
});

Events::trigger('payment.captured', 100);  // → "first capture: 100"
Events::trigger('payment.captured', 200);  // → (nothing — once fires once)

Or, on the low-level emitter:

use InitPHP\Events\EventEmitter;

$emitter = new EventEmitter();
$emitter->once('payment.captured', function ($amount) { /* … */ });
$emitter->emit('payment.captured', [100]);
$emitter->emit('payment.captured', [200]);

Removing listeners

off() (facade / Event) and removeListener() (low-level) drop a specific callable; removeAllListeners(?string) wipes one event or every event. Listener identity is strict — keep a reference to the closure you want to remove.

$audit = function (array $order) { /* … */ };

Events::on('order.placed', $audit);
Events::off('order.placed', $audit);

Events::removeAllListeners('order.placed');   // one event
Events::removeAllListeners();                 // every event

What's next?

  • The full surface of the Events facade — including simulate and debug modes.
  • The full surface of the EventEmitter — including once, removeListener, and removeAllListeners.
  • A grab-bag of real-world patterns: Recipes.
  • The complete API Reference.

Clone this wiki locally