PHP Class Loading and WordPress Plugins
WordPress plugin development can be an absolute pain.
That’s right. I said it. Coding plugins for clients and keeping that code neat and tidy can be a nightmare.
The best way to write your code (in most cases) to prevent conflicts and keep code together is to use classes.
The problem comes when you need multiple classes to separate your code. What is the best way to load your classes? That depends. Let’s take a look at some of the ways you can load classes.
Standard Include
1 2 3 4 |
require_once 'includes/My_Awesome_Class.php'; $awesome = new My_Awesome_Class(); // OR My_Awesome_Class::Awesome_Method(); |
The simplest way to make a class available. Just include or require the file. You can then instance your class or use any static functions.
Returned Include
Another method is to instance your class and return it. For example in My_Awesome_Class.php
you may have the following:
1 2 3 4 5 6 7 8 9 10 |
// My_Awesome_Class.php class My_Awesome_Class { public function __construct() { // Do something Awesome } } return new My_Awesome_Class(); |
This might look a little unusual if you haven’t seen it before. The return keyword can be used in a file. When that file is included whatever was returned will be provided. For example:
1 2 3 4 5 |
// My_Awesome_Plugin.php $awesome = require_once 'includes/My_Awesome_Class.php'; //$awesome now contains an instance of My_Awesome_Class() |
This can be somewhat helpful to provide an easy way for other developers to access classes in your plugin. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// My_Awesome_Plugin.php class My_Awesome_Plugin { public $classes; public function __construct() { $this->classes = new StdClass(); $this->classes->My_Awesome_Class = require_once 'includes/My_Awesome_Class.php'; $this->classes->My_Super_Class = require_once 'includes/My_Super_Class.php'; } } $My_Awesome_Plugin = new My_Awesome_Plugin(); |
Using this method other developers can access your main plugin class and all it’s sub-classes via the variable you have provided.
SPL Autoload
My favorite method of loading classes is to use PHP’s built in spl_autoload_register()
function.
If you are unfamiliar with spl_autoload_register()
it allows you to define a function that will load your class when you try to use it. That is regardless of if you are trying to call a static method or instance a class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// My_Awesome_Plugin.php class My_Awesome_Plugin { public function __construct() { $this->init(); } private function init() { // Define Plugin path if ( ! defined( 'MAP_DIR' ) ) { define( 'MAP_DIR', trailingslashit( dirname( __FILE__ ) ) ); } spl_autoload_register( $this, 'autoload_register'); } public function autoload_register($class_name) { // Make sure it is our class that wants to be loaded if ( 0 !== strpos( $class_name, 'MAP' ) ) { return; } $path = MAP_DIR . 'includes'; if(file_exists("{$path}/{$class_name}.php")) { include_once("{$path}/{$class_name}.php"); } } } $map_main = new My_Awesome_Plugin(); |
This is just one way I’ve used autoloading in the past. The function you pass to spl_autoload_register()
will receive the name of the class being called.
Your function should take the name and try to load the relevant file. This is one of the reasons it is good to stick with a naming convention for your classes.
In this case the autoload function checks the requested class has our project prefix (MAP) and if the file actually exists. Files that contain classes are named in the same way as the class itself. So My_Awesome_Class
would be held in a file called My_Awesome_Class.php
.
That’s all there is to it. Now if you try to instance a class or use a static method from any classes PHP will try to automatically include the file for you.
You can also define multiple autoloaders. For example, if you are using the awesome CMB2 in your WordPress plugin they also use SPL autoloading. PHP will just run each autoloader in turn.
Even more good news when using the SPL autoloader. It does not cause any problems with using Composer’s autoloader.
Wrapping Up
In this post we’ve looked at how you can load classes in a WordPress plugin, and with PHP in general.
Which method you would use is entirely up to which suits your project. There are other methods such as using PSR4 autoloading via Composer, that method would require the use of Namespaces and is something outside the scope of this article.
4 Comments
Manny Fleurmond
So if you call require_once multiple times with the same file, it’ll return a new instance every time??
Paul Robinson
Hi Manny,
No. Any following requires of the same file will produce a boolean with the value
true
as noted in the PHP documentation. I’ll edit the article to mention this as after a quick search I hadn’t realized how many questions on sites like Stack Overflow there were onrequire
andinclude
This is why it is a matter of choice as to which method is best for your project. If you are going to be creating multiple instances it is better to either simply require/include the file and instance to a variable or use the SPL autoloader if there are going to be a lot of classes to load.
Manny Fleurmond
A tangent by mind is still reeling that you can use return in an included file:
I’m assuming it would be possible to return out of an included file early, like you would a function if your condition was already met/not met/etc. Real world example is I was helping with a WordPress plugin where the author wrapped classes in if statements to prevent collisions if the class was accidentally included in another plugin ie if( !class_exists($classname) ) {/*define class here */}. Wouldn’t it make sense you could do if( class_exists($classname) ) { return; } to the same effect?
Paul Robinson
Hi Manny,
Yes, you could technically use return to exit the script if the class already exists. I can’t see any reason why it would be bad to do so, but I believe it is considered best practice to enclose the class in the class existence check.
Just remember to be careful of using
return
incorrectly, as noted by the PHP docs:Meaning you should always use
exit()
,die()
or in the context of WordPresswp_die()
if you need to end all code execution. I’ve seen many examples of this used incorrectly so I wanted to make sure I mentioned it.