How to autoload classes and interfaces in Drupal 7

While we wait for the "at least" Drupal 8 RC to start upgrading our websites and finally be able to use tons of advanced features like Namespaces and PSR-4 autoloading 1, let's admit - rock solid version 7 of Drupal will be our primary development framework for years from now and we should learn how to live with it.

But even with Drupal 7, born in early 2011 (oh my!), we absolutely should do things "in the right way" and not to forget about generations of developers to come to support (and upgrade) our shiny websites. Using best practices and following standards becomes more important as ever.

Let's take a look at one of the less known trick, which might get handy in many situations when you need to put your custom logic in a separate class or build a PHP interface to make your code more organized.

Imagine we've created a helper class in the entity_helper.inc file which allows to manipulate a custom entity, like this:

class EntityHelper {

  /**
   * Returns some value from a custom property.
   */
  public static function getValue($entity_type, $entity, $property, $langcode = NULL) {

    // Put your logic here.
    return $property;
  }
}

Next, we want to have an option to access it from everywhere in our application to be able to do things like $get_property = EntityHelper::getValue('my_entity', $entity, 'custom_value');

Include or require

Yes, we can still use the traditional PHP way to do things, but while possible, this is not recommended (for mostly aesthetic reasons, see my next point below):

$path = drupal_get_path('module', 'name_of_module');
require_once $path .'/entity_helper.inc';  

Use module_load_include()

module_load_include() does one simple thing - it loads a module include file. So go ahead like this:

module_load_include('inc', 'name_of_module', 'includes/entity_helper');  

Pay attention - no need to specify the file extension in the last argument!

Many use this this function without knowing what it actually does. But just for fun be aware - it uses exactly require_once() from my previous point, but only in a Drupal friendly way. So whenever you want to include a regular include file, think of module_load_include().

Using the module's .info file

Now the tricky part.

Not all types of files or custom functions can be autotoloaded by simply declaring them in the module's .info file. According to brilliant documentation 2, ONLY classes and interfaces can be autoloaded in this way.

 > Drupal 7 uses a code registry - an inventory of all classes and interfaces for all enabled modules and Drupal's core files. The registry stores the path to the file that a given class or interface is defined in, and loads the file when necessary. The registry loads classes and interfaces on demand, via php's built in class autoloading mechanism. 

This sounds like a good place for our class! So let's just do it in name_of_module.info file:

files[] = entity_helper.inc  

And after rebuilding the registry we're good. Our class and methods inside just became available to the entire application.

Using PSR-4 autoloading from Drupal 8

That's right. It is possible, in Drupal 7, to have some cool stuff from Drupal 8 right now, without a need for an upgrade. Enter the X Autoload module, which does exactly that.

You can do things like this for example and many others (like using Namespaces):

files[] = includes/*.inc  

I'm really not sure why would one use this, as in my personal opinion it makes the Drupal 7 code even more bloated than it is now and just adds extra complexity. We should follow our framework standards as much as possible, and this is simply not a standard for this particular framework. I'm not talking about maintainability here and don't mention the fact that it will entirely depend on the developer who decided to use this tool in the first place.

However, ~8000 installs prove I might be wrong.

What's your opinion on this? Do share in comments.

  1. https://www.drupal.org/node/2156625 PSR-4 namespaces and autoloading in Drupal 8

  2. https://www.drupal.org/node/350780 Drupal 7's code registry