If you are writing object-oriented code an autoloader is a must-have. Without an autoloader you would need to add a line with including the class file, before you can initialize it. It can quickly be cumbersome when you work with a lot of classes. An autoloader is a function that triggers everytime a new class is instantiated, and includes the class file before instantiation happens.
Namespaces are a way of structuring and encapsulating your code, and helps avoiding name collisions. If you are going to write OOP, it’s recommended to use namespaces as well. Keep in mind that you can implement an autoloader without using namespaces in your OOP code.
You can use this code for your WordPress theme or plugin, or any PHP code outside WordPress for that matter – just modify the paths correspondingly. For this example I’m creating an autoloader for a WordPress theme.
Rules for class namespace and structure
Implementing an autoloader would require some defined rules for your code structure and where to find them. Using namespaces simplifies this somewhat, as your namespace can refer to which folder the classes are in.
First make a decision of what your namespace should be named. Usually it’s something unique for your code, for example your theme name. For example, the namespace for this site’s theme is AWhitePixel\Theme
. This means that for the autoloader to work, any classes must be inside this namespace.
namespace AWhitePixel\Theme;
My first rule is that any class file will always contain only one class, and the class name must be the same as the file name. For example; a class MyTest
must be defined inside a file MyTest.php
.
My second rule is how to structure the classes in folders. I decide that all classes goes inside a folder src
in my theme. I can put class files directly in this folder, and for that they must be inside “root” namespace defined above. But if I want to create subfolders and put class files in them, their namespaces must include the folder structure. For example a class file MyTest.php
that resides in the folder src/Test/
, must have this namespace defined:
src/Test/MyTest.php
namespace AWhitePixel\Theme\Test;
Creating the autoloader
I like to keep the autoloader in a separate file, and outside the src/
folder which is defined for namespaced class files only. As an example I’ll create a file autoloader.php
in the folder inc/
in my theme.
PHP has a built-in autoloader function: spl_autoload_register. You provide your autoloader function name as parameter, and in that function you get the requested class as argument (what you put after new
when instantiating the class). When instantiating classes with namespaces, e.g. new AWhitePixel\Theme\Test\MyTest()
, the provided variable to this function would be "AWhitePixel\Theme\Test\MyTest"
.
Let’s add the autoloader function, and in it we define our required namespace for the autoloader:
inc/autoloader.php
<?php spl_autoload_register('awhitepixel_autoloader'); function awhitepixel_autoloader($class) { $namespace = 'AWhitePixel\Theme'; }
Then we need to include this file so that our autoloader is registered. As this is in a theme, I’ll add the include in the theme’s functions.php
. If you are using this for a plugin, put it inside your plugin files. The autoloader file needs to be added early, before any instantiation of classes. I’m putting this at the very first line in my functions.php
:
functions.php
require_once(get_template_directory() . '/inc/autoloader.php');
If you are using it for a child theme, or a plugin, modify the path for your needs.
And that’s it. Now the autoloader is in place, but it’s not doing anything. Let’s return to the autoloader function and finish it.
Writing and testing the autoloader function
First we need to ensure that the requested class name is actually inside our namespace. We simply check if the namespace class name provided contains the namespace string, and if not, exit the function. After that we remove the namespace name from the string, so that we can work out any subfolders and class file.
inc/autoloader.php
<?php
spl_autoload_register('awhitepixel_autoloader');
function awhitepixel_autoloader($class) {
$namespace_name = 'AWhitePixel\Theme';
if (strpos($class, $namespace) !== 0) {
return;
}
$class = str_replace($namespace, '', $class);
}
Now we’ll transform the provided namespace into an actual path to the file. First, we’ll replace any backslash "\"
in the namespace with the character for folder separator – for this we use the PHP constant DIRECTORY_SEPARATOR
. At the very end we add a ".php"
. And finally before the string we add the full root path. Because this is inside a theme, I’m using get_template_directory()
. If you are using this for a plugin, use a method that returns the full path to your plugin.
inc/autoloader.php
...
$class = str_replace($namespace, '', $class);
$class = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
$directory = get_template_directory();
$path = $directory . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $class;
}
All we need to do now is to check if the file exists, and if it does, require it.
inc/autoloader.php
...
$path = $directory . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $class;
if (file_exists($path)) {
require_once($path);
}
}
That’s it!
Let’s test it out. Create a subfolder Test
in your theme’s src/
folder, and inside it put a php file named MyTest.php
. Define a class MyTest
in it, following the rules for namespace: AWhitePixel\Theme\Test
. I’ll just add a print of ‘Success’ in the construct function so we can easily see that it actually initializes the class.
src/Test/MyTest.php
<?php namespace AWhitePixel\Theme\Test; class MyTest { public function __construct() { var_dump('Success!'); } }
In our functions.php, after requiring the autoloader, we simply instantiate the class:
functions.php
$test = new AWhitePixel\Theme\Test\MyTest();
Refresh your WordPress site and see that you get the ‘Success!’ outputted.
The autoloader will autoload any class files that are inside our defined namespace, and follows the correct rules. You can instantiate classes from anywhere inside your theme, even inside the classes themselves.
The full autoloader function
For reference, here’s our final autoloader function:
inc/autoloader.php
spl_autoload_register('awhitepixel_autoloader'); function awhitepixel_autoloader($class) { $namespace = 'AWhitePixel\Theme'; if (strpos($class, $namespace) !== 0) { return; } $class = str_replace($namespace, '', $class); $class = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php'; $directory = get_template_directory(); $path = $directory . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $class; if (file_exists($path)) { require_once($path); } }