Introduction to PSR-14 & Event Dispatching Unification

Introduction to PSR-14 & Event Dispatching Unification

A brief introduction on why standardizing Event Dispatching is a good thing, and how we achieved this with PSR-14. Also with personal opinion


Benni Mack

August 04, 2019


  1. Introduction to PSR-14 An Interoperable Event Dispatcher @bennimack

  2. About Benni • Got infected with PHP in 1999 •

    Running as CTO • TYPO3 Project Lead • Involved in PHP-FIG as working group member of PSR-14 • Grateful husband & father of two
  3. What’s PHP-FIG?

  4. About PHP Framework Interoperability Group • Find solutions for common

    issues within PHP projects and libraries bring communities together since 2009 • Strives for greater interoperability for PHP projects • Consists of a Core Committee, Secretaries and Member Project Representatives • PSR = PHP Standards Recommendation • If you’ve ever used PHP seriously in the last 5 years, you’ve already used PSRs
  5. PSRs heavily used in the wild • PSR-1 + 2:

    Spaces vs. Tabs • PSR 3: Ever heard of monolog? • PSR 0 + 4: Autoloading • PSR 7 + 15 + 17 + 18: Immutable HTTP-related interfaces • PSR 6 + 16: Cache + Simple Cache
  6. Why standardize event dispatching?

  7. What’s the issue with Event Dispatchers? • symfony/event-dispatcher • league/event

    • doctrine/event-manager • Laravel’s event dispatcher • Drupal: “hooks” and symfony events • TYPO3: “hooks”, signals etc. • Wordpress: “hooks” • Magento 2: Overload of Proxy Classes with around/before/after • Composer plugin system
  8. Why is event dispatching important?

  9. Events allow to extend your library / app

  10. Events as in... • One way notification - “Something happened,

    just wanted to let you know” • Object enhancement - “Something is about to happen, add/modify before I do it” • Collection - “Give me all your things, I may do something with it” • Alternative Chain - “Something is about to happen, check if somebody can do it” • Event Sourcing - out-of-scope
  11. Single pieces • Event - a message ◦ Some create

    an object or a call-by-reference array ◦ a string as identifier - some add a final class Events { const BEFORE_INSERT = ‘beforeInsert’; } ◦ Could have arguments / properties via new EventArgs() • Listener ◦ Some call it observers, or subscribers ◦ Do something now or maybe later (deferred) • Listener Provider ◦ Collects all listeners • Event Dispatcher - send the message ◦ Executes registered listeners in the callers code (Emitter) ◦ Want to do with the results?
  12. What’s there to standardize?

  13. None
  14. $dispatcher->dispatchEvent(‘beforeRendering’, [‘json’ => true]); $dispatcher->dispatch(new BeforeRenderingEvent()); $dispatcher->on(‘beforeRendering’); $dispatcher->until(Events::UNTIL_LOADED, new EvtArgs([‘json’

    => true));
  15. Challenges 1. Find the most of least common denominator 2.

    Don’t keep living in PHP 5.2 world for a future-proof recommendation 3. Don’t limit existing APIs, but allow new things to flourish
  16. None
  17. Hard facts and key takeaways • Identify an event by

    a PHP object ◦ No strings, no FQDN of Classes, no “anonymous” events with just arguments ◦ No “event name” ◦ Inheritance of classes / interfaces “built-in” already via PHP core • Separate dispatching and listener registration • Immutability cannot be ensured by interfaces ◦ Return the event object that is given back again to the caller
  18. Dispatcher Interface A dispatcher receives an event (a “message”) and

    after processing, returns it back. interface EventDispatcherInterface { /** * @param object $event * The object to process. * * @return object * The Event that was passed, now modified by listeners. */ public function dispatch( object $event); }
  19. Registration Process - Providers A listener provider collects listeners of

    the system and injects them into the dispatcher interface ListenerProviderInterface { /** * @return iterable[callable] * An iterable (array, iterator, or generator) of callables. Each * callable MUST be type-compatible with $event. */ public function getListenersForEvent( object $event) : iterable; }
  20. Providers can be magic --- or not • Built-in “by

    convention” providers possible onRequestStart(RequestStartEvent $evt) • Gather all available listeners at compile time? Done. • Libraries can build dependency concepts or priority / ordering concepts (0-100 vs. “after plugin XYZ”) • Collect multiple providers together in one (AggregateProvider)
  21. Event object What’s an event then? Where’s the spec? final

    class MyTemplateNameModifierEvent { private $templateName; public function __construct(string $templateName) { $this->templateName = $templateName; } public function getTemplateName() : string; public function setTemplateName(string $templateName) : void; }
  22. The code in the wild Create an event, dispatch it,

    boom. public function main() { $evt = new MyTemplateNameModifierEvent(‘tmpl/Home.html’); $evt = $this->eventDispatcher->dispatch($evt); $view = $this->initializeView($evt->getTemplateName()); return $view->render(); }
  23. You’re gonna WANT to create listeners Change the template to

    something else - but only for the late night visitors class MyListener { public function lateNightTemplate(MyTemplateNameModifierEvent $evt) { if (date(‘G’) >= 18) { $evt->setTemplateName(‘tmpl/LateNight.html’); } return $evt; } }
  24. One more thing… A Stoppable Event Events where listeners have

    already fulfilled the job, can be stopped interface StoppableEventInterface { public function isPropagationStopped() : bool; }
  25. Main egoistic benefits

  26. The beauty for me as PHP project author • TYPO3

    can use one generic EventDispatcher, and pull in sources from all kinds of places • So extensions can actually just hook into Symfony components the same way as in TYPO3 • TYPO3 has all available events documented and objectified • Old “hooks” will just become listeners
  27. The beauty for me as PHP coder • I know

    what kind of information an event contains • I know what I can change for a mutable event • I know that it’s the same concept for all the PHP libraries I use (hopefully)
  28. Wait! There is more... • Deferred listeners possible ◦ Swoole

    & ReactPHP have PoCs • Use events for things there are no good solutions yet ◦ Authentication chains can be built as events • Check out the blog series on PSR-14 by @Crell ◦ make sure to follow him on Twitter and Steemit (
  29. Summary • Decoupled Dispatcher & Registration • Events are identified

    via objects, no Marker Interface • Built-in Stoppable Events • Listener Providers can integrate anything • Approved in March 2019 • Requires PHP 7.2+ • Forward compatible w/ Symfony 5 • Existing implementations ◦ Tukio -- @Crell ◦ Kart -- @bennimack ◦ Phly Event Manager -- @mwop
  30. Thanks. Questions? … and don’t forget: implement PSR-14. @bennimack