Provide different versions of ModuleHandler::invokeAll() for performance

Created on 31 March 2017, about 8 years ago
Updated 14 January 2025, 3 months ago

ModuleHandler::invokeAll() contains some costly logic to recursively merge results from hook implementations.

In some cases this recursive merging is not needed, or even undesirable.
In some cases, the return value is not needed at all.

Alternative methods could be provided for these cases, promising performance improvements and an overall simpler and more predictable behavior.

These alternative methods could be part of ModuleHandler, or they could live in a separate class that depends on ModuleHandlerInterface.
The latter option would allow to introduce this change without changing the interface.

Developers could then decide which version of the method they want to call.

Example implementation:

  public function invokeAllReturnNothing($hook, array $args) {
    foreach ($this->moduleHandler->getImplementations($hook) as $module) {
      $function = $module . '_' . $hook;
      call_user_func_array($function, $args);
    }
  }

  public function invokeAllReturnArraySum($hook, array $args = array()) {
    $return = array();
    foreach ($this->getImplementations($hook) as $module) {
      $function = $module . '_' . $hook;
      $module_result = call_user_func_array($function, $args);
      if (NULL !== $module_result && is_array($module_result)) {
        $return = $module_result + $return;
      }
    }
    return $return;
  }

and maybe this one for completeness..

  public function invokeAllReturnKeyed($hook, array $args = array()) {
    $return = array();
    foreach ($this->getImplementations($hook) as $module) {
      $function = $module . '_' . $hook;
      $return[$module] = call_user_func_array($function, $args);
    }
    return $return;
  }

I am sure that other optimizations could be made to ModuleHandler::invokeAll(). But this should happen in separate issues.

πŸ“Œ Task
Status

Active

Version

11.0 πŸ”₯

Component

extension system

Created by

πŸ‡©πŸ‡ͺGermany donquixote

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

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡ΊπŸ‡ΈUnited States nicxvan

    Do you have examples of the types of hooks for each?

  • πŸ‡ΊπŸ‡ΈUnited States nicxvan
  • πŸ‡©πŸ‡ͺGermany donquixote

    Looking at ->invokeAll() calls, here are some examples for the most common types.

    No return value:
    hook_cache_flush()
    hook_rebuild()
    hook_(entity|ENTITY_TYPE)_(presave|insert|update|predelete|delete|revision_create)()
    hook_entity_bundle_create()
    hook_entity_bundle_delete()

    Merge:
    hook_updater_info()
    hook_filetransfer_info()
    hook_requirements()
    hook_update_requirements()
    hook_entity_preload()
    hook_(entity|ENTITY_TYPE)_(access|create_access)()
    hook_field_info_max_weight()
    hook_entity_extra_field_info()
    hook_entity_operation()

    We could investigate if these all need the same merge logic.
    I am looking at ->invokeAllWith() calls now..

  • πŸ‡©πŸ‡ͺGermany donquixote

    The most obvious first step here would be a dedicated logic for hooks with no return value and regular passing of parameters, so the first group in my previous comment.
    I am not sure how much improvement this would bring, seems like a micro optimization.
    If we only measure the raw overhead from the module handler, it will make a difference. If we measure total request time it will be overshadowed by other things.

  • πŸ‡©πŸ‡ͺGermany donquixote

    And yes this part still applies with the new event hook system.

  • πŸ‡©πŸ‡ͺGermany donquixote

    Actually, if we inline most of the stuff in invokeAll() we probably get some improvement.
    We can do this in the other issue πŸ“Œ Optimize ModuleHandler::invokeAll() Active .
    Perhaps the remaining benefit from separate methods per return value behavior would have diminishing returns after that other optimization.

Production build 0.71.5 2024