Drupal 11.1 Adds Hooks as Classes: A History, How-To, and Tutorials We’ve Updated

With the release of Drupal 11.1, there’s a cool new feature for developers: Hooks can now be implemented as class methods using PHP attributes instead of functions. This change is a major step forward in modernizing Drupal’s codebase. While procedural function-based hooks are still supported (and will be for some time), developers writing new code should strongly consider using the object-oriented (OOP) approach introduced in Drupal 11.1.

A brief history of hooks in Drupal

The concept of hooks — functions that follow a defined naming convention and are invoked at specific points during Drupal’s runtime — has been a part of Drupal for a very, very, long time. I think it’s safe to say that they are one of Drupal’s most defining features. And virtually un-changed for 24 years. Until now.

The idea of PHP functions that follow a defined naming convention as a way to allow modular code was first added to Drupal this commit [#8d5b4e7b] on Dec. 23rd, 2000.

[#be8e898d]. This updates includes the addition of the module_invoke function below. And the introduction of this line of code $function = $name ."_". $hook; which has basically been with us ever since.

[#456fd7cc] to use call_user_func_array() which amongst other things allowed hooks at have any number of arguments. Note the use of $a1 ... $4 which prior to this limited the number of arguments a hook could receive.

[#c80c3e18]), this code was moved into the ModuleHandler::invoke() method, and updated to make use of some newer PHP language features, but the logic remained the same. And the code stayed this way until Drupal 11.1:

public function invoke($module, $hook, array $args = []) {
    if (!$this->hasImplementations($hook, $module)) {
        return;
    }
    $hookInvoker = Closure::fromCallable($module . '_' . $hook);
    return call_user_func_array($hookInvoker, $args);
}

In Drupal 11.1, the logic for calling a function based hook is now in ModuleHandler::legacyInvoke(), but is still basically the same:

protected function legacyInvoke($module, $hook, array $args = []) {
    $this->load($module);
    $function = $module . '_' . $hook;
    if (function_exists($function) && !(new ReflectionFunction($function))->getAttributes(LegacyHook::class)) {
        return $function(...$args);
    }
    return NULL;
}

Kind of amazing how well this system has served Drupal for 24 years. Drupal 8 introduced new patterns for altering, extending, and enhancing Drupal core like plugins, services, and events. But hooks are still an important part of how the system works.

Object-oriented hook implementations

The idea of switching to object-oriented hook implementations has been around for a long time. And numerous attempts have been made since the introduction of Drupal 8. But for various reasons, some technical and some DX related, the solution was elusive until recently.

Before Drupal 11.1, implementing a hook meant writing a procedural function following a specific naming convention in your .module file, like this:

/**
 * Implements hook_form_alter().
 */
function mymodule_form_alter(&$form, DrupalCoreFormFormStateInterface $form_state, $form_id) {
  // Custom code and comments go here ...
}

Now, with Drupal 11.1+, we can implement hooks inside classes using the #[Hook] attribute. Example code lives in src/Hook/MyModuleFormHooks.php:

<?php
declare(strict_types=1);

namespace DrupalmymoduleHook;

use DrupalCoreFormFormStateInterface;
use DrupalCoreHookAttributeHook;

class MyModuleFormHooks {

  /**
   * Implements hook_form_alter().
   */
  #[Hook('form_alter')]
  public function formAlter(&$form, FormStateInterface $form_state, $form_id): void {
    // Custom code and comments go here ...
  }

}

Why use OOP hooks instead of the traditional procedural function-based hooks?

Improved code organization and readability

  • Hooks are now encapsulated within classes, reducing clutter in .module files.
  • Instead of having multiple hook functions scattered across a .module file, related hooks can be grouped logically inside a single class.

Enables autowiring and dependency injection

Class-based hooks support dependency injection, allowing services to be injected directly into the class. This eliminates the need for Drupal::service() calls, making code more testable and modular.

Example:

namespace DrupalmymoduleHook;

use DrupalCoreLoggerLoggerChannelFactoryInterface;
use DrupalCoreHookAttributeHook;

class MyModuleHooks {
  protected LoggerChannelFactoryInterface $loggerFactory;

  public function __construct(LoggerChannelFactoryInterface $loggerFactory) {
    $this->loggerFactory = $loggerFactory;
  }

  #[Hook('cron')]
  public function cron() {
    $this->loggerFactory->get('mymodule')->info('Cron job executed.');
  }
}

Better testability

Unit tests become easier since hooks are now inside classes that can be instantiated with mocked dependencies. The procedural approach required global function mocking, which was cumbersome.

PSR-4 Autoloading and performance

Since class-based hooks follow PSR-4 autoloading, they aren’t loaded unless needed. This contrasts with .module files, which are always loaded, even if they contain only hook functions that might not be used. Reducing unnecessary file loading can lead to minor performance improvements.

TL;DR:

✅ Better code organization

✅ Supports dependency injection (no more Drupal::service())

✅ Easier to test

✅ Performance benefits

✅ Future-proof (aligns with modern PHP practices)

If you’re writing new Drupal 11.1+ code, the OOP approach is the way to go! 🚀

Updating our tutorials with the new approach

One of our core commitments at Drupalize.Me is ensuring that our tutorials remain accurate and relevant as Drupal evolves. So, we’re working on updating all of our tutorials to take into account the new OOP approach to adding hooks in a module. Procedural hooks have been around for 24 years. We know they aren’t going to disappear overnight. You’ll see them in example code and existing documentation for a long time to come. For now, we’ll be including both approaches in our content whenever doing so makes sense.

You should plan on learning both approaches, and then using the one that makes the most sense given your specific case.

Notable tutorial updates

  • What Are Hooks?: This tutorial now covers the concept of hooks, their purpose, and the new OOP implementation method introduced in Drupal 11.1.
  • Implement Any Hook: Updated to guide developers through the process of implementing hooks using both traditional procedural functions and the new class-based approach with attributes.

The Drupal Module Developer Guide has been thoroughly updated to ensure compatibility with Drupal 11.1, incorporating the new OOP methodologies for hook implementations.

Similar Posts

  • The best products to sell online in 2025

    Whether you’re starting your first business, looking for new products to sell, or launching your tenth brand, navigating the rapidly evolving world of ecommerce to sell products requires thorough research and a sharp focus on trends and strategies. Successful online businesses understand the importance of making informed decisions at every step of the research and…

  • 100 Most Cited Domains in Google’s AI Mode

    Article Performance Data from Ahrefs Linking websites The number of websites linking to this post. Get the week’s best marketing content We analyzed our Brand Radar database of 5.5 million AI Mode queries to identify the domains that appear most often in Google’s AI Mode responses. These are the 100 most cited domains, along with…

  • 7 Best PHP Hosting Server Providers in 2025,Jul

    Are you looking for an efficient and versatile website hosting solution?  Why not try hosting based on the PHP scripting language? Choosing a hosting is a daunting task especially when you have so many options!  The hosting solution that you choose must have certain technical capabilities and functionality so that your project can develop and…

  • 10 Best Linux Distros for Hosting 2026,Jan (Top Picks)

    Is your website still running slowly even after you’ve an expensive hosting service? Working on a computer that crashes again and again can be very frustrating. The problem might be with your operating system, not the server. Because the outdated OS lacks new features, creates laggy performance and an unresponsive system. So the only solution…

  • ServiceNow Knowledge 2024: New Generative AI Features Unveiled

    In May 2024, a 20,000 strong ServiceNow community descended on Las Vegas for 3 days of breakout sessions, training, thought leadership, networking, and partying at Knowledge 24. Knowledge is ServiceNow’s flagship annual conference for customers, partners, and advocates. Although the event is typically centred around customer stories, there were several exciting new announcements that we’ll…

  • Finding New Opportunities for Your WordPress Agency

    The business model for running a WordPress agency has changed in recent years. It used to be that we had an overflow of new projects coming our way. Business was plentiful, and there was little reason to think outside the box. That’s no longer the case. These days, it seems like everyone already has a…