[policy, no patch] Encourage hooks over event subscribers

Created on 9 December 2024, about 2 months ago

Problem/Motivation

hooks are deeply rooted in Drupal with many benefits.
In recent years I think there has been hesitancy to add new hooks since they required procedural implementations.

Developers would use event dispatcher and event subscribers to get hook like effects while writing OO code. Alternatively they would write a service and the hook implementation was just a wrapper.

Now that hooks are event listeners and can be OOP (with some exceptions) we can take advantage of autowiring and the event system without the more verbose subscriber system.

As for the differneces:

Listeners and subscribers can be used in the same application indistinctly. The decision to use either of them is usually a matter of personal taste. However, there are some minor advantages for each of them:

Subscribers are easier to reuse because the knowledge of the events is kept in the class rather than in the service definition. This is the reason why Symfony uses subscribers internally;
Listeners are more flexible

https://symfony.com/doc/current/event_dispatcher.html#listeners-or-subsc...

Event subscribers have always felt like an attempt at hook like behavior rather than a replacement.

I think we should begin to encourage developers to consolidate on #[Hook] implementations so there is one way to interact.

Anecdotally it looks like most projects are moving towards attribute driven event listeners over subscribers as well.

Steps to reproduce

N/A

Proposed resolution

Make the policy to prefer hook implementations again over event dispatcher directly.

Remaining tasks

Discuss

User interface changes

N/A

Introduced terminology

TBD

API changes

TBD

Data model changes

TBD

Release notes snippet

๐Ÿ“Œ Task
Status

Active

Version

11.0 ๐Ÿ”ฅ

Component

base system

Created by

๐Ÿ‡บ๐Ÿ‡ธUnited States nicxvan

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @nicxvan
  • ๐Ÿ‡จ๐Ÿ‡ญSwitzerland znerol

    I do prefer using events in many situations for the exact same reason other people dislike them: Introducing an event requires introducing a custom value object class. Introducing a hook doesn't.

    For code authors, the event class is a good place to document requirements and expectations for an extension point. I know there is mymodule.api.php but in my personal experience, I cannot be trusted to keep that up-to-date. Even more so because I do not have any tooling for my IDE to display hook documentation where it would be most useful (i.e. when I implement hooks). With the event pattern, the docs are available where the event is used.

    I think the event value object class having its own distinct type reduces accidents due to type confusion and it simplifies static code analysis. But I guess that hook implementations could be just as safe with a set of phpstan rules examining hook implementation parameters.

    For code users, the event class is handy to quickly navigate to places where an event is dispatched or where it is handled. Sure, I can grep for Implements hook_XYZ (or nowadays #Hook('XYZ')) and just hope that I find every implementation. But I do enjoy the fact that my IDE is able to quickly list every usage of an event class with built-in tooling. No magic needed at all.

    My gut feeling is that hooks have their strengths when operating on loosely typed stuff (e.g., form structures, render arrays, processing of twig variables, etc.). On the other hand, events are best used in conjunction with clearly defined types (e.g., UserFloodEvent operating on a user entity in core or the commerce_order.order.paid event operating on an order in commerce).

  • ๐Ÿ‡ฆ๐Ÿ‡บAustralia acbramley

    I see where you're going with #2 but there is no reason that I know that a Hook can't use a value object too, right? Some already get entity objects (e.g entity_insert) so you could do the exact same thing that you do with an event?

  • ๐Ÿ‡จ๐Ÿ‡ฆCanada Charlie ChX Negyesi ๐ŸCanada

    The plan is to introduce subclasses of Hook and move the doxygen from api.php there. There are nuances around dynamic hooks, that discussion is at ๐Ÿ“Œ [PP-1] Determine how to implement Form Alters with attributes. Active .

  • ๐Ÿ‡ฎ๐Ÿ‡ฉIndonesia el7cosmos ๐Ÿ‡ฎ๐Ÿ‡ฉ GMT+7

    I wouldn't say hook implementations can replace event dispatcher altogether.

    I can add a listener to the event dispatcher dynamically on runtime.

    $anon = new class {
      public function userCancel(): void {
      }
    };
    $eventDispatcher->addListener(UserCancelEvent::class, [$anon, 'userCancel']);
    

    When the event is dispatched, the anonymous class's method is called. However, the same thing does not work with hook implementations.

    $eventDispatcher->addListener('drupal_hook.user_cancel', [$anon, 'userCancel']);
    

    I'm not sure if this is a bug or if this is intended, but at the very least there is a feature missing if we want to replace event dispatcher.

  • ๐Ÿ‡จ๐Ÿ‡ฆCanada Charlie ChX Negyesi ๐ŸCanada

    Please file a feature request for that; it needs to go on ModuleHandler and not the event dispatcher.

Production build 0.71.5 2024