An observer receives events from a publisher without coupling the publisher to every downstream action.
What It Does and When to Use It
Implement a simple dispatcher with separately registered listeners. Direct PHP code exposes the underlying operation clearly; a framework can supply lifecycle hooks, dependency wiring and retries.
Requirements, Inputs and Expected Behavior
Confirm the runtime, extension, environment variables, and permissions before running the examples in production. Keep listeners predictable, isolate failures and avoid recursive event chains.
Example 1: Basic Operation
Implement a simple dispatcher with separately registered listeners.
<?php
final class Dispatcher {
private array $listeners = [];
public function on(string $name, callable $listener): void { $this->listeners[$name][] = $listener; }
public function dispatch(string $name, object $event): void {
foreach ($this->listeners[$name] ?? [] as $listener) $listener($event);
}
}
$events = new Dispatcher();
$events->on('invoice.created', static function (object $e): void { echo $e->id; });
$events->dispatch('invoice.created', (object)['id' => 23]);
Example 2: Behavior and Validation
Separate several reactions from the action that published an event.
<?php
$handlers = [static fn (int $id) => "audit:$id", static fn (int $id) => "email:$id"];
$results = array_map(static fn (callable $f) => $f(42), $handlers);
print_r($results);
Practical Example: Application Use
Pass structured event data and keep validation explicit.
<?php
$listeners = [];
$listeners['order.paid'][] = static function (array $event): void {
if (($event['amount'] ?? 0) <= 0) throw new InvalidArgumentException('Positive amount required');
echo 'Recorded payment ', $event['id'];
};
foreach ($listeners['order.paid'] as $listen) $listen(['id' => 'p-13', 'amount' => 85]);
Important Behavior and Edge Cases
The second example highlights: Separate several reactions from the action that published an event. The practical example adds: Pass structured event data and keep validation explicit.
Comparison with Related Approaches
| Approach | What changes |
|---|---|
| Direct operation versus framework-managed integration | Direct PHP code exposes the underlying operation clearly; a framework can supply lifecycle hooks, dependency wiring and retries. |
| Choosing safely | Choose based on deployment requirements and verify actual behavior rather than assuming defaults. |
Common Beginner Mistakes
| Mistake | Correct approach |
|---|---|
| Assuming successful execution proves the result is usable | Check the return value, required extension, and observable output of the specific operation. |
| Ignoring runtime and environment differences | Verify PHP version, SAPI, operating system, service access, and permissions before deployment. |
| Skipping operational constraints | Keep listeners predictable, isolate failures and avoid recursive event chains. |
Key Takeaways
- An observer receives events from a publisher without coupling the publisher to every downstream action.
- Pass structured event data and keep validation explicit.
- Choose based on deployment requirements and verify actual behavior rather than assuming defaults.