Managing .module file using hook_hook_info

Did you know? Using hook_hook_info, so we can reduce the size of loc in .module file and we can segregate  all the hooks in a single  custom module file.

Since all .module files get read and executed  for every Drupal menucallback execution, the size of the .module file directly impacts  performance. The .module file should always have just the necessary amount of code. hook_hook_info helps us to segregate & move all hook specific code to a separate file.

The Performance advantage is minimal when opcode caching is used. It still servers helps is managing code.

I am going to explain hook_hook_info with an example module (my_module.module). my_moudle.module uses  4 hooks (list below). 

Example :

Module name = my_module.module.

1) hook_node_insert

2) hook_node_delete

3) hook_comment_insert

4) hook_comment_delete

my_module.module file will have the below content:

function my_module_hook_info() {
$hooks['node_insert'] = array(
'group' => 'node'
);
$hooks['node_delete'] = array(
'group' => 'node'
);
return $hooks;
}

Create a separate inc file for all the groups. In our example we need two inc file one for ‘node’ and another for ‘comment’. The inc file should be in the format $module.$group.inc to be picked up by hook_hook_info(). In my example the inc files are:

1) my_module.node.inc

2) my_module.comment.inc

Inside my_module.node.inc declare :

function my_module_node_insert($node) {
dpm($node);
}

function my_module_node_delete($node) {
dpm($node);
}

Inside my_module.comment.inc declare :

function my_module_comment_insert($comment) {
dpm($comment);
}
function my_module_comment_delete($comment) {
dpm($comment);
}

When a Drupal hook is executed, Drupal triggers module_invoke_all. If your module uses a hook either directly in the module or by using  hook_hook_info(), the associated inc files will get invoked. The inc files also get triggered from module_invoke for the associated hook.

The sequence of functions executed,  how and where the inc files get included

For a specific hook, module_invoke_all is triggered, followed by module_implements. In module_implements the hook_info implementations are obtained from module_hook_info(). This is then parsed and the inc files are loaded in a loop. The below lines of code in the module_implements is what does these actions:

foreach ($list as $module) {
$include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
// Since module_hook() may needlessly try to load the include file again,
// function_exists() is used directly here.
if (function_exists($module . '_' . $hook)) {
$implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
}
}

In my case, the above the line will include my_module.node.inc, my_module.comment.inc at runtime for the corresponding  hooks node and comment.

Use this feature to your advantage, reduce the size of your module files!

Example

SHARE ON: 

Comments 9

Never knew about this hook, and looks like a solution to organize the module as well (form alters, node API, menu, etc).
Can you provide a downloadable file so we can see the actual code ?

Good luck!

do you have any examples of modules using this approach? I've never heard of that hook but this makes perfect sense, never came across it in contrib previously. Would love to see a real world performance metric of using the approach vs not using the approach but that'd be pretty hard to rig up to scale.

Nice article. I would say this technique is most useful for maintaining clean code and grouping together functionality, rather than for performance.

Assuming you're using an opcode cache such as APC or Zend Opcache (which is a must for any Drupal site), the module code size won't really be an issue, as every module file will be pre-processed and held in shared memory after the first usage, so won't need to be loaded from disk each time.

There can be a small overhead for each file included, so having a greater number of files may actually decrease performance very slightly, however in practice this is going to be negligible and PHP 5.3 (recommended for Drupal 7) includes a number of performance optimisations when including php files which all but eliminates this overhead.