call_user_func_array() and named arguments in PHP 8 -> ModuleHandler

Created on 19 September 2022, over 2 years ago
Updated 27 August 2024, 4 months ago

Problem/Motivation

This ticket is basically https://www.drupal.org/project/drupal/issues/3174022 โ†’ but it's another place in the code making problems.

I just checked my Drupal instance's compatibility with PHP 8.1. it works quite well so far. Only one thing doesn't work, yet. I did some debugging and found the issue in the core:

web/core/lib/Drupal/Core/Extension/ModuleHandler.php

Here we have calls of call_user_func_array but the args are not processed with array_values:

 /**
   * {@inheritdoc}
   */
  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);
  }

  /**
   * {@inheritdoc}
   */
  public function invokeAll($hook, array $args = []) {
    $return = [];
    $this->invokeAllWith($hook, function (callable $hook, string $module) use ($args, &$return) {
      $result = call_user_func_array($hook, $args);
      if (isset($result) && is_array($result)) {
        $return = NestedArray::mergeDeep($return, $result);
      }
      elseif (isset($result)) {
        $return[] = $result;
      }
    });
    return $return;
  }

Hence I get:

Error: Unknown named parameter $message in call_user_func_array() (line 427 of core/lib/Drupal/Core/Extension/ModuleHandler.php).

Proposed resolution

Use array_values so that in php 8.x the $args's keys aren't used for named properties:

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

  /**
   * {@inheritdoc}
   */
  public function invokeAll($hook, array $args = []) {
    $return = [];
    $this->invokeAllWith($hook, function (callable $hook, string $module) use ($args, &$return) {
      $result = call_user_func_array($hook, array_values($args));
      if (isset($result) && is_array($result)) {
        $return = NestedArray::mergeDeep($return, $result);
      }
      elseif (isset($result)) {
        $return[] = $result;
      }
    });
    return $return;
  }

Remaining tasks

Test case
Code review
Testing

๐Ÿ› Bug report
Status

Needs work

Version

11.0 ๐Ÿ”ฅ

Component
Baseย  โ†’

Last updated 3 days ago

Created by

Live updates comments and jobs are added and updated live.
  • PHP 8.1

    The issue particularly affects sites running on PHP version 8.1.0 or later.

  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

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

Production build 0.71.5 2024