Implementing custom hooks in Drupal

I'm sure this has been covered to death elsewhere but it's been forever since I posted anything and this is what I spent today working on so I figured I'd go ahead and do a quick writeup nonetheless.

Why use a hook?

Any number of reasons. My favorite is definitely giving others (and yourself) an easy way to extend or otherwise modify the behavior of a module without having to resort to hacking on it. This ability comes in especially handy if you have a large module you've broken down into a core module and a series of helpers since it provides a very clean and convenient method of extending the core module's behavior.

In many situations the alternative would be implementing a small API in your core module, which generally means a ton of extra function declarations. For example, during a recent refactoring project I was able to eliminate two include files worth of related function calls by reimplementing a chunk of the core module as a hook.

So what do I need?

Surprisingly, not much; module_invoke_all() handles all of the drudge work. Let's take a look at a simple example code.

<?php
  /**
   *  custom module function with custom hook
   */
function mymodule_hello(){
  $names = array();
  /*this is where the magic happens*/
  $names = module_invoke_all('mymodule_names');
  foreach($names as $name){
    print "Hello, $name\n";
  }
}

?>

In the example above we've created code to handle a new hook: hook_mymodule_names. module_invoke_all will call every implementation of hook_mymodule_names present in any modules enabled on your site. Whatever value these return is added to an array and the result array is returned by module_invoke_all. Note hooks are called in alphabetical order by module name unless the module weight has been explicitly set.

Here's what a sample implementation of hook_mymodule_names might look like:

<?php

/**
 * implementation of hook_mymodule_names
 */
function mynewmodule_mymodule_names(){
  $name = 'Aaron';
  return $name;
}

Assuming mynewmodule is enabled, our original function should print 'Hello, Aaron'.

One major caveate to using custom hooks would be potential namespace issues. You want to be very careful what you name your hooks to avoid calling a random function within another module. The common approach is usually naming the hook hook_modulename (example: hook_block or hook_user). This should guard against possible collisions with other modules.

A word on argument passing

While module_invoke_all() supports passing arguments to hooks that it invokes, I just found out today (much to my dismay) that it apparently does not support pass-by-reference. There are workarounds available for this issue though. You can opt to write your own function, or use a global variable (suboptimal, but it works).

Tags:

Freeman on web stuff

If it's wrong, bad or
stupid, let me just say that
I am not surprised.

- author unknown

User login

Navigation

More Drupal hotness

Powered by Drupal, an open source content management system