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

  • Taiwan NSB Alerts Public on Data Risks from TikTok, Weibo, and RedNote Over China Ties

    Jul 05, 2025Ravie LakshmananNational Security / Privacy Taiwan’s National Security Bureau (NSB) has warned that China-developed applications like RedNote (aka Xiaohongshu), Weibo, TikTok, WeChat, and Baidu Cloud pose security risks due to excessive data collection and data transfer to China. The alert comes following an inspection of these apps carried out in coordination with the…

  • 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…

  • My Exact 7-Step Framework for Brand SEO (With Templates)

    Branding wasn’t something SEOs traditionally thought much about. The real wins were in non-branded keywords, where the traffic and conversions lived.  However, that changed when Google and OpenAI turned most of these queries into zero-click searches. For the remaining queries, search platforms directly reward authoritative and popular brands, so branding can no longer be ignored…

  • 9 Best Dedicated Server in India 2026, February🇮🇳Top Picked

    Have you ever struggled with controlling your server environment? Or found yourself frustrated due to unexpected downtimes and server crashes, especially during malicious traffic attacks that you never saw coming? These challenges are common when you’re relying on low-quality hosting services that can’t handle sudden spikes. That’s where Best Dedicated Server Hosting in India steps…

  • Tips for Streamlining Your Web Development Workflow

    Web development is an ever-evolving industry. That means we’re constantly adapting to what’s new, all while maintaining quality and efficiency. No sooner are we comfortable with something than it changes on us. This applies to our workflow just as much as it does to other parts of our business. The way we build websites must…

  • AI is changing how shoppers find your products

    AI is already reshaping how shoppers discover, compare, and purchase products. Here’s what’s happening, why it matters, and what WooCommerce merchants should know right now. If you sell online, the way your customers find you is changing. Half of all consumers now use AI when searching the internet, according to McKinsey. Shoppers are asking ChatGPT…