What are the magic functions buying us? In my experience, developers are confused when they start trying to figure out where what is getting called by whom. Plus, we have lots of expensive aparatus for discovering these functions and maintaining reliable lists of them. We don't respond well to state changes (like modules moving to a new directory, or two versions of the same module in the code base. And it's also a relatively inflexible structure. We can't, for instance, declare that I want hook_x to run, but I want it to ran after some other module runs its hook_x (okay we can with crazy alter functions, but it is pretty intense.

This pattern would follow a more typical observer pattern, similar to the one that is used in jQuery with events:

function mymodule_init($drupal) {
$drupal->tellMeAbout('menu', 'mymodule_menu');
// could even...
$drupal->runABeforeB('menu', 'someothermodule','mymodule');
}

Modules would remain the same, they would simply need to add some kind of function to the top of the module file which every module would have to declare. It would be an easy thing to script with coder.

This would solve a lot of our problems IMO, and help DX a lot while only forcing module maintainers to add a very small amount of code. If others are interested in what I admit is a somewhat radical departure of the land of magic functions, I will draft up a patch. I don't think it would take too long.

As an aside, other modules could use this pattern since we are using dependency injection with the event registry / controller thing being passed in. So the views module could let its submodules / includes register hooks that are specifically only for views.

Comments

joachim’s picture

This would be in a way a generalization of hook_node_info()'s concept of 'base', or hook_forms() system of mapping one form name to a different callback.

A few comments:

- jbrown's proposal for namespaces in D8 addresses this problem in a different -- and more radical -- way
- for modules that just want to do the usual MODULE_HOOKNAME, we should provide a helper to make this easier: tellhelper('MODULE', 'hook_a', 'hook_b'....) and that can produce the more verbose array.
- should probably not be in mymodule_init but in something whose results get cached.

JacobSingh’s picture

I just used hook_init as an example. But really, it could be anything. Basically, you need one magic function to register that it will be responsible for doling out responsibility. You could also just declare hook implementations in an info file I suppose.

Caching could still be done, just like we do for hook_menu.

Best,
Jacob

JacobSingh’s picture

stupid tag added

pillarsdotnet’s picture

+1

pillarsdotnet’s picture

Sounds like a job for hook_hook_info().

pillarsdotnet’s picture

Title: Stop using magic functions and force modules to declare the hooks they want to implement. » Require all hooks to be declared via hook_hook_info().
agentrickard’s picture

Title: Stop using magic functions and force modules to declare the hooks they want to implement » Require all hooks to be declared via hook_hook_info().

[edit] Removing comment because it was OT from this issue. See #1373884: [meta] Core does not use hook_hook_info() instead.

agentrickard’s picture

Issue tags: +API clean-up

The implementation ticket is #624324: Do not load support code for optional core modules for moving functions to files.

sun’s picture

Title: Require all hooks to be declared via hook_hook_info(). » Stop using magic functions and force modules to declare the hooks they want to implement

Note that #624324: Do not load support code for optional core modules relies on the automatic discovery of hook implementations. It makes all core modules register all hooks they are exposing (which others can implement). This is about API providers.

That's not the same as having every module register which hooks it implements. This is about API consumers.

I'd like to see an example implementation for this in this issue first.

And as these are completely different operations, hook_hook_info() would be a slightly confusing place to implement the registry for API consumers. Therefore, let's discuss the implementation first, before shortcutting it and settling on hook_hook_info().

Lastly, please note that hook_hook_info() is a very poor construct currently, and before advancing on it, we need to solve a range of major issues:
#968264: hook_hook_info() can lead to an infinite loop
#1029158: Let hook_hook_info() handle hooks in .install files (aka "rename MODULE.install to MODULE.install.inc")
#825854: Module_implements should cache the file path and not TRUE/group value for hooks that specify group in hook_hook_info()
#451152: Implementing a hook on the behalf of another module

And eventually, this issue seems to be a duplicate of #983470: Improve lazy-load mechanism for procedural code

agentrickard’s picture

Should we not implement the existing API first and then clean it up?

agentrickard’s picture

@sun

I was pointed here from a duplicate issue. Reading the whole thread, it looks like comments 6-7 shifted the focus of this issue.

That said, I'd still like to implement the code we have before refactoring the entire hook system.

sun’s picture

Hm, "Require all hooks to be declared via hook_hook_info()" sounds like a goal that is different to the OP here.

If I get the OP right, then the proposal discussed in this issue is:

In order to implement hook_foo() in your module and have it invoked by the module system, you have to do:

function yourmodule_hook_implementation_info() {
  return array(
    'foo',
  );
}

Without this code, yourmodule_foo() is unknown to the system and thus not invoked.

The OP merely uses an OO based approach, but the net gain/proposal is identical.

agentrickard’s picture

Yes. Agreed. I'm going to move my stuff back to my original issue. #1373884: [meta] Core does not use hook_hook_info().

Sorry for the distraction.

ralf.strobel’s picture

Title: Require all hooks to be declared via hook_hook_info(). » Stop using magic functions and force modules to declare the hooks they want to implement

This is an interesting discussion. Maybe I can contribute by explaining how I first misunderstood the purpose of hook_hook_info(), because the way I wanted it to work seems quite like what you intend...

I thought that hook_hook_info() worked on a module level, so that I could define files to be included when hooks are called specifically for my module. For instance, I wanted to place all the cached definitions like hook_theme(), hook_menu(), hook_block_info() into a separate "mymodule.info.inc", so that this file would only be lazy-loaded whenever the cache has to be rebuilt.

I was really disappointed when I learned that hook_hook_info() only works globally. But maybe a good, backward-compatible solution would be to make it work both ways:

function mymodule_hook_info() {
  $hooks['some_lazy_hook'] = array(
    'group' => 'lazy',
    'global' => FALSE,
  );
}

Whenever the 'global' attribute, which defaults to TRUE, is set to FALSE, the hook group definition would be exclusive to mymodule, invoking mymodule.lazy.inc whenever mymodule_some_lazy_hook() is called.

I believe this functionality would only require relatively minor changes to module_hook_info() module_hook(), module_implements() and module_invoke() to make it work.

Of course it remains to be seen how necessary this will still be, as soon as the core finally implements the existing hook_hook_info() to a reasonable degree, as just posted by agentrickard in #14.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

andypost’s picture

Status: Active » Closed (duplicate)