Beyond Prefixing: A WordPress Developer’s Guide to PHP Namespaces

Prefix everything.

It is an adage that is old as the WordPress software itself. Prefixing has been a standard for WordPress developers for so long that it’s hard to imagine doing anything different. But, the time has come for something new. Well, it is long past due, but WordPress lags a bit behind in standard practices in the larger PHP world.

Prefixing is the practice of creating a code-friendly version of your project name and sticking it to the front of functions, classes, and other things in the global namespace. For example, you would name a function tavern_get_post() instead of get_post() to avoid function name clashes, which would result in a fatal error.

Prefixing is one form of “namespacing,” which is just a fancy way of saying that names in this space belong to a specific project. However, prefixing (and suffixing, which is less common) is a hack from a time when no solution existed for the PHP language.

PHP 5.3 introduced an official method of namespacing, so the standard has existed for years. Because WordPress 5.2 bumped the minimum PHP requirement to 5.6, it is time for developers to shed their old habits and catch up to the rest of the PHP world.

Namespace (Almost) Everything

PHP namespacing only covers the following items.

  • Classes
  • Interfaces
  • Traits
  • Functions
  • Constants declared with the const keyword but not define()

When it comes to script handles, image size names, database options, and other items in the global namespace, you must still prefix them. Those are IDs and outside the scope of PHP namespacing.

How to Create Namespaces

Namespaces are simple to declare. At the top of any PHP file that you want to use a particular namespace, declare it as shown in the following code snippet.

<?php

namespace Tavern;

What this line of code does is declare that everything within this particular file has the namespace of Tavern.

Take a look at a simple function under that namespace for outputting a Hello, World! message.

<?php

namespace Tavern;

function hello() {
    _e( 'Hello, World!', 'example-textdomain' );
}

If following the old rules of prefixing, hello() would have been named tavern_hello(). However, that’s not the case with namespaces. The hello() function is encapsulated within the Tavern namespace and will not conflict with other functions named hello().

Classes and interfaces work the same as functions. With a class name of Article, the class file might look like the following.

<?php

namespace Tavern;

class Article {
    // ...
}

Note: There should only ever be one class or interface per file. This is particularly important if you ever plan to use an autoloader.

How to Name Namespaces

Developers like to argue over how to name things, and there is no one-size-fits-all solution. The most important rule is to be unique to avoid clashes with code from other projects. One of the best ways to do that is to use a top-level Vendor namespace with a Package sub-namespace.

Suppose the vendor namespace was Tavern and the project in question was a WordPress theme named News. The namespace for the project might look like the following.

<?php

namespace TavernNews;

That may be a bit verbose for some developers. If your project’s name is already fairly unique, such as “Awesomesauce,” you may simply want to use the following.

<?php

namespace Awesomesauce;

You will want to come up with some sort of standard convention, at the very least, for yourself. Eventually, you’ll want to get into things like auto-loading, so having a system you follow in all your projects will help. Feel free to peruse the PHP-FIG Autoloader standard.

Importing Classes and Functions into a Different Namespace

When you need to use a class or function from a different namespace than the current namespace, you need to import it. This is done via the use keyword in PHP.

The use statement must come after the namespace declaration. It should also reference the fully-qualified class name. The following code imports the TavernHelpersPost class into a file with a different namespace.

<?php

namespace TavernTemplate;

use TavernHelpersPost;

Once it is imported, you are safe to use the Post class directly as shown in the next snippet.

$post = new Post();

As of PHP 5.6, you can also import functions and constants from other namespaces using the use function and use const keywords, respectively. The following code block demonstrates how to import both a function and a constant.

<?php

namespace TavernTemplate;

use function TavernHelpersfunc_name;
use const    TavernHelpersCONSTANT_NAME;

Aliasing Classes and Functions

Eventually, you will run into a situation where you need to import a class or function that has the same name as a class or function within the current namespace. You might be thinking that this is the problem that namespaces were meant to solve. Fortunately, PHP provides a method of creating an alias on import.

Suppose you have a class named TavernUser and need to implement the TavernContractsUser interface. When importing the interface, you will need to create an alias as shown below.

<?php

namespace Tavern;

use TavernContractsUser as UserContract;

class User implements UserContract {
    // ...
}

The as UserContract appended to the end of the use statement creates an alias for the User interface. You can safely use the new UserContract name without error.

Classes, interfaces, functions, and constants all follow the same method for creating an alias.

Organizing Folder Structure Based on Namespaces

It is standard practice in the wider PHP world for namespaces and the project’s file and folder structure to match. Doing this makes it easy for other developers to easily locate code within your project. It also makes it simple to build autoloaders for loading classes on demand.

Generally, all PHP code should go into a /src, /inc, or similarly-named folder in your project. An example plugin file and folder structure might look like the following.

/plugin-name
    /src
        /Core
            /Activate.php
            /Setup.php
        /View
            /Post.php
            /Page.php

If following the same structure with namespaces, the above .php files would contain the following classes.

  • TavernCoreActivate
  • TavernCoreSetup
  • TavernViewPost
  • TavernViewPage

Take note that file and folder names are case-sensitive and should match the namespace and class name exactly.

Of course, you are free to follow any convention that you wish. However, the preceding recommendation is good practice and will simplify how you organize your projects in the long term.

Benefits of Using Namespaces

The most obvious benefit is to avoid clashes between classes and functions with the same name. You should use real namespaces for the same reason you used prefixes.

Namespaces help to avoid long class names. Typing long names throughout a large project is a tedious practice at best.

More easily switch implementations by importing. Once you get the hang of importing classes and interfaces from other namespaces, you can switch an implementation of an interface with a single line of code.

Autoloading classes is far easier if you follow the PSR-4: Autoloader standard, which requires at least a top-level namespace.

For developers in the professional space, you will gain a marketable skill beyond the WordPress ecosystem. You will be hard-pressed to find PHP development work if you don’t know how to use namespaces. It is not a tough concept to grasp, but there can be a learning curve for some in practice.