PHP Namespaces, Autoloaders and WordPress

Namespaces aren’t used by WordPress programmers, but I’ve been using them, and like them. This short tutorial explains namespaces, and how they work together with class autoloaders to keep your code organized.

What are namespaces? It’s a way to keep function and class names from clashing. Imagine that you have two scripts that both define foo(). You can avoid name clashes by using namespacing:

<?php // file: bar.php
namespace JK\BAR;

function foo() {
   # stuff
}

The above will not clash with the code below.

<?php // file: goo.php
namespace JK\GOO;

function foo() {
   # stuff
}

The first file’s function has a longer formal name, JK\BAR\foo(). The second file’s function is JK\GOO\foo().

If you want to call the first foo() from the second script, you use JK\GOO\foo(). This doesn’t happen too often, except when you use WordPress’ pubsub/events system:

add_action( 'some_action', 'JK\GOO\foo' );

See what we did there? The second argument is a Callable, and a string with a path to a namespaced function is a callable.

The WordPress coding style advocates using a static class to encapsulate functions. For example:

class BAR {
    function foo() { ... }
}

class GOO {
    function foo() { ... }
}

That works in a similar way. I don’t dislike it… but I prefer namespaces. Here are three ways to call foo in GOO, the first two work when foo is a static function, and the last is for instances of classes.

add_action( 'some_action', 'GOO::foo' );
add_action( 'some_action', array('GOO', 'foo') );
add_action( 'some_action', array($goo, 'foo') );

Classes give you a little more flexibility… but namespaces are simpler.

Namespaces, Classes and Autoloaders

I’m surprised that WordPress classes are named like WP_Query and our own are supposed to be named like Vendor_Something_MyClass. I thought this stuff went away with namespaced classes. You can use a namespace like this:

namespace Vendor\Something;

class MyClass {
}

Then the full name of the class is Vendor\Something\MyClass.

It looks a little less terse… but you can do some magic with autoloaders and paths to help organize your code libraries.

What’s an Autoloader?

Autoloaders are functions that take class names as arguments, and then call include to include the class’ definition sources. Here’s an example of an autoloader that will load the above class, if the definition of MyClass is stored in Vendor/Something/MyClass.php:

function autoload(String $class) {
    if ($class == 'Vendor\Something\MyClass') {
         include 'Vendor/Something/MyClass.php';
    }
}
spl_autoload_register('autoload');

Now, your PHP code can use the class like this:

$x = new Vendor\Something\MyClass();

The “magic” here is that you no longer need to put include 'Vendor/Something/MyClass.php'; at the top of your script. If Vendor\Something\MyClass isn’t already defined, PHP will pass the name of the class to the autoload function. The autoload function then includes the file.

The above example is pretty fake: it only loads one class. A real autoloader mangles the classname so it maps to a directory hierarchy in the filesystem.

namespace JK\PROJECT;

function autoload($class) {
    include str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
}
spl_autoload_register('JK\PROJECT\autoload');

You might be thinking it’s inefficient to mangle strings every time you load a class. It might be. That’s why tools like Composer will compile the complete paths into code, so lookups are faster, and merge it with a template for an autoloader class.

I think str_replace is probably faster than hashing and searching an associative array.

Use

The use keyword is the last bit of syntactic sugar. I don’t use it much, because a long pathname to a class is explicit, but here’s how use works:

namespace JK\PROJECT;

use \Vendor\Something\MyClass as MyClass;

$obj = new MyClass();

use is like import in other languages. It aliases the long class names to the short class name, so you can have shorter code.

How often do you need to instantiate a class in multiple places in your code? It’s generally not often.

I hope this was pretty simple. Namespaces, classes, and autoloaders are separate language features, but they were designed to work in tandem, to help make you code libraries more manageable, and to get rid of the complex ordering of include which plagued PHP code for years.

Leave a Reply