Justin Tadlock

PHP Namespaces For WordPress Developers

Laptop sitting on a table with a notepad and pen in front of it.

It seems like ages ago when I stopped working with PHP 5.2, which is currently the minimum version to run WordPress. One of the primary reasons for this for me as a developer was to use PHP namespaces, introduced in PHP 5.3. There are many other useful features brought to the language in the past decade, but namespacing is one of my favorites.

With talk of WordPress bumping the minimum PHP version in 2019, I figured it was finally time to wrap up this post on why plugin and theme authors should be making the switch to proper namespaces now (or, rather should’ve already made the switch).

I encourage you to read the official PHP namespace documentation once you’ve finished this post, which will give you a more in-depth look over what you can do. This post is merely a primer and will cover the foundation of namespaces.

What are PHP namespaces?

In a nutshell, namespacing is a method of grouping all of your code under a custom name. That way, your classes, functions, and so on don’t clash with other people’s code running on the site at the same time.

If you create a class named Post and another plugin creates a class named Post, you get a fatal error. Developers have long dealt with this by prefixing their class names with something like Justin_, creating the Justin_Post class. Prefixing is one form of namespacing your code. However, prefixing is not formally supported by the language. There are no features built specifically for working with it.

With the release of PHP 5.3, the first iteration of an officially-supported namespaces came into being. Now, our fully-qualified Post class name becomes Justin\Post with Justin being the namespace.

If you’ve been prefixing function or class names, you’ve already been namespacing your code. Cool. Now, you can take it to the next level and use the officially-supported method.

How to create namespaces

To create a namespace for any particular class or group of functions, you need to declare the namespace at the top of the file. No other code should come before your namespace declaration other than the opening <?php tag or comments.

Here’s an example of a single class file (files with a class should only have that one class and no other functions or classes):

namespace Justin;

class Post {}

Here’s an example of a file with functions:

namespace Justin;

function do_something() {}

function do_something_else() {}

Once you’ve declared the namespace at the top of the file, all code within the file will be under that namespace.

Importing code from a different namespace

Let’s suppose we have a post helper class in our theme or plugin as shown in the following code block.

namespace Justin\Helpers;

class Post {}

We need to reference that in another namespace. For that, we’d utilize the use statement to import the Post class. use statements should come after the namespace declaration.

namespace Justin\Template;

use Justin\Helpers\Post;

class View {

	public function display() {
		$post = new Post();
	}
}

You can also use an alias for the Post class if you wish. In the following example, we give the Post class an alias of PostHelper.

namespace Justin\Template;

use Justin\Helpers\Post as PostHelper;

class View {

	public function display() {
		$post = new PostHelper();
	}
}

If you want to import a function instead of a class, the use statement is a little different. In the following example, use becomes use function.

use function func_name;

Referencing namespaced classes directly

You don’t necessarily need to import a class or function to use it outside its namespace. You can call the class using the fully-qualified class name.

$post = new \Justin\Helpers\Post();

For one-off uses, that makes a quick way to call up a class or function.

Autoloading and organization

No tutorial on namespaces would be complete without digging into the PSR-4: Autoloader standard. This is the standard used by the wider PHP development world. One day, I hope that WordPress itself will embrace it. While autoloading isn’t strictly related to namespaces, I’ve found that most developers who begin using namespaces almost immediately start seeing the benefits of autoloading.

Autoloading is a method of automatically loading class files when a given class is called. In the past, you may have been including all classes like in the following example.

require_once( __DIR__ . '/class-a.php' );
require_once( __DIR__ . '/class-b.php' );
require_once( __DIR__ . '/class-c.php' );

And, anytime you changed, added, or removed a class, you were forced to change your loading code. With autoloading, you no longer have to do that. Your classes are simply loaded when you call them. This also cuts back on the amount of code that you load at any given time. If a class isn’t called on a particular page, it’s simply not loaded. While this is unlikely to be a bottleneck in any particular application, we should still strive for that sort of efficiency in our code where possible.

The PSR-4 standard provides a couple of important things:

  • Method for naming classes, traits, and interfaces.
  • Rules on file and folder naming based on those classes.

Given our earlier classes of Justin\Helpers\Post and Justin\Template\View, your plugin files may be ordered something like the following.

plugin.php
	/src
		/Helpers
			/Post.php
		/Template
			/View.php

PSR-4 doesn’t say you need the /src folder, but it’s a widely-used convention. I prefer it as “the place where your PHP source code lives.”

The folders below /src follow our namespacing and class-naming rules.

  • Each sub-namespace gets its own folder (case-sensitive).
  • Each class gets its own file (case-sensitive).
  • Justin, the primary namespace, is not used. If you wished, you could use it as a folder.

Basically, the folder and file structure matches the fully-qualified class names. This simplicity makes autoloading easy.

Standards are good for development communities. By following PSR-4, it means that most PHP developers can pick up your code and immediately figure out where things are. Over the years of reviewing both theme and plugin code in the WP community, there’s nothing I dreaded more than not being able to find things because of some custom organizational system.

Autoloading with Composer

If you utilize Composer, which is outside the scope of this tutorial, autoloading classes is as simple as configuring the autoload argument in your composer.json:

"autoload"    : {
	"psr-4" : {
		"Justin\\" : "src/"
	}
},

Composer will handle autoloading your classes from there.

Custom autoloading

If you’re not using Composer, you’ll need to register an autoloader. I’ve included a sample one below. There are others out there that may suit you better.

spl_autoload_register( function( $class ) {

	$namespace = 'Justin\\';
	$path      = 'src';

	// Bail if the class is not in our namespace.
	if ( 0 !== strpos( $class, $namespace ) ) {
		return;
	}

	// Remove the namespace.
	$class = str_replace( $namespace, '', $class );

	// Build the filename.
	$file = realpath( __DIR__ . "/{$path}" );
	$file = $file . DIRECTORY_SEPARATOR . str_replace( '\\', DIRECTORY_SEPARATOR, $class ) . '.php';

	// If the file exists for the class name, load it.
	if ( file_exists( $file ) ) {
		include( $file );
	}
} );

Start using namespaces today

Just because core WordPress hasn’t updated to newer versions of PHP doesn’t mean you can’t user newer features in your own plugins and themes. I’ve been running my most popular plugin on PHP 5.6+ this year with few user issues. Even those were just a matter of getting the user to upgrade from their Web host’s control panel.

Namespaces are widely-used throughout out the larger PHP development community. Getting used to working with them will help you better understand general PHP code when you come across other projects.

Like this tutorial? Please consider helping me write more in the future by making a donation via PayPal, grabbing something from my Amazon Wish List, or signing up at Theme Hybrid where you can ask me any support questions you want.