I just found the piece of information that was missing.
EDIT: And another one.
Problem with module_invoke()
module_invoke_all() always calls
module_implements(), which checks the module include file by checking both
module_invoke() only checks
hook_hook_info() and not
module_invoke() is called e.g. in
This means that
hook_module_implements_alter() is not a good solution to split a
hook_block_view() implementation into a separate file.
This has been a problem in Crumbs, see https://www.drupal.org/node/2328535.
For other hooks it generally works ok, but you never know if a specific module wants to use
module_invoke() instead of
module_implements() cache polluted in bootstrap.
Another problem is caused by a core issue reported here:
module_implements_cache() can be polluted by hook_boot() implementations calling module_invoke_all() directly or indirectly
This applies only to non-boot modules, where it can happen that the implementation of
hook_module_implements_alter() is never discovered.
- An unexpected chain of events causes
module_implements($hook) being called from
$hook can be any random hook, it does not need to be related to the module we are working on.
- This causes
module_implements('module_implements_alter') to be called.
- Drupal looks for all implementations of
At this time,
MODULENAME.module is not included yet.
Therefore, for the rest of the request, Drupal assumes that the implementation
MODULENAME_module_implements_alter() does not exist.
- Later in the request, implementations of other hooks are being discovered, but the implementations by MODULENAME are not being found, because
MODULENAME_module_implements_alter() is not being executed.
Alternatives have already been mentioned. Instead of these tricks, one can include the file directly. There may be a tiny performance impact but this is probably overshadowed by a lot of other things in Drupal.
But, instead of using
module_load_include(), I would suggest a more direct solution:
require_once __DIR__ . '/crumbs.block.inc';
Or to be PHP 5.2 compatible:
require_once dirname(__FILE__) . '/crumbs.block.inc';
Why not module_load_include()?
There is generally no need to call
module_load_include(), it could even be detrimental, if the *.module file is included from you-dont-know-where (e.g. from
settings.php), and you don't know if
module_load_include() is available.
This function is mostly there to help you determine the location of other modules. But if you are including within the same module, it is generally safer and easier and faster to work with relative file paths and explicit
Call to helper function
As mentioned by Jimajamma, you can also implement the hook in the main
*.module file, and then include another file and call a helper function from there. This is done e.g. in Display suite.
This solution is ok, although I think it still clutters the main file, and gives you even more places to look.
And here likewise you can use require_once instead of
module_load_include(), if it is within the same module.