Arriving here exactly 2 years after the original question was asked, there are a few things I want to point out. (Don\'t ask me to point out a lot of things, ever).
Proper hook
To instantiate a plugin class, the proper hook should be used. There isn\'t a general rule for which it is, because it depends on what the class does.
Using a very early hook like "plugins_loaded"
often make no sense because an hook like that is fired for admin, frontend and AJAX requests, but very often a later hook is far better because it allows to instantiate plugin classes only when needed.
E.g. a class that does stuff for templates can be instantiated on "template_redirect"
.
Generally speaking it is very rare that a class needs to be instantiated before "wp_loaded"
has been fired.
No God Class
Most of all the classes used as examples in older answers use a class named like "Prefix_Example_Plugin"
or "My_Plugin"
... This indicates that there probably is a main class for the plugin.
Well, unless a plugin is made by one single class (in which case naming it after plugin name is absolutely reasonable), to create a class that manages the entire plugin (e.g. adding all the hooks a plugin needs or instantiating all the other plugin classes) can be considered a bad practice, as an example of a god object.
In object oriented programming code should tend to be S.O.L.I.D. where the "S" stand for "Single responsibility principle".
It means that every class should do a single thing. In WordPress plugin development it means that developers should avoid to use a single hook to instantiate a main plugin class, but different hooks should be used to instantiate different classes, according to the class responsibility.
Avoid hooks in constructor
This argument has been introduced in other answers here, however I want to remark this concept and link this other answer where it has been pretty widely explained in the purview of unit testing.
Almost 2015: PHP 5.2 is for zombies
Since 14 August 2014, PHP 5.3 reached its end of life. It\'s definitely dead.
PHP 5.4 is going to be supported for all 2015, it means for another year at the moment I\'m writing.
However, WordPress still supports PHP 5.2, but no one should write a single line of code that support that version, especially if code is OOP.
There are different reasons:
- PHP 5.2 dead a long time ago, no security fixes are released for it, that means it isn\'t secure
- PHP 5.3 added a lot of features to PHP, anonymous functions and namespaces über alles
- newer versions of PHP are a lot faster. PHP is free. Updating it is free. Why use a slower, insecure version if you can use a faster, more secure one for free?
If you don\'t want to use PHP 5.4+ code, use at least 5.3+
Example
At this point it is time to review older answers based on what I said until here.
Once we don\'t have to care about 5.2 anymore, we can and should, use namespaces.
For sake of better explain the single responsibility principle, my example will use 3 classes, one that does something on the frontend, one on the backend and a third used in both cases.
Admin class:
namespace GM\\WPSE\\Example;
class AdminStuff {
private $tools;
function __construct( ToolsInterface $tools ) {
$this->tools = $tools;
}
function setup() {
// setup class, maybe add hooks
}
}
Frontend class:
namespace GM\\WPSE\\Example;
class FrontStuff {
private $tools;
function __construct( ToolsInterface $tools ) {
$this->tools = $tools;
}
function setup() {
// setup class, maybe add hooks
}
}
Tools interface:
namespace GM\\WPSE\\Example;
interface ToolsInterface {
function doSomething();
}
And a Tools class, used by the other two:
namespace GM\\WPSE\\Example;
class Tools implements ToolsInterface {
function doSomething() {
return \'done\';
}
}
Having this classes, I can instantiate them using proper hooks. Something like:
require_once plugin_dir_path( __FILE__ ) . \'src/ToolsInterface.php\';
require_once plugin_dir_path( __FILE__ ) . \'src/Tools.php\';
add_action( \'admin_init\', function() {
require_once plugin_dir_path( __FILE__ ) . \'src/AdminStuff.php\';
$tools = new GM\\WPSE\\Example\\Tools;
global $admin_stuff; // this is not ideal, reason is explained below
$admin_stuff = new GM\\WPSE\\Example\\AdminStuff( $tools );
} );
add_action( \'template_redirect\', function() {
require_once plugin_dir_path( __FILE__ ) . \'src/FrontStuff.php\';
$tools = new GM\\WPSE\\Example\\Tools;
global $front_stuff; // this is not ideal, reason is explained below
$front_stuff = new GM\\WPSE\\Example\\FrontStuff( $tools );
} );
Dependency Inversion & Dependency Injection
In the example above I used namespaces and anonymous functions to instantiate different classes at different hooks, putting in practice what I said above.
Note how namespaces allow to create classes named without any prefix.
I applied another concept that was indirectly mentioned above: Dependency Injection, it is one method to apply Dependency Inversion Principle, the "D" in SOLID acronym.
The Tools
class is "injected" in the other two classes when they are instantiated, so in this way it is possible to separate responsibility.
In addition, AdminStuff
and FrontStuff
classes use type hinting to declare they need a class that implements ToolsInterface
.
In this way ourselves or users that use our code may use different implementations of the same interface, making our code not coupled to a concrete class but to an abstraction: that\'s exactly what Dependency Inversion Principle is about.
However, the example above can be further improved. Let\'s see how.
Autoloader
A good way to write better readable OOP code is not to mix types (Interfaces, Classes) definition with other code, and to put every type in its own file.
This rule is also one of the PSR-1 coding standards1.
However, doing so, before being able to use a class one needs to require the file that contains it.
This can be overwhelming, but PHP provides utility functions to auto load a class when it is required, using a callback that loads a file based on its name.
Using namespaces it becomes very easy, because now it is possible to match the folder structure with the namespace structure.
That\'s not only possible, but it is also another PSR standard (or better 2: PSR-0 now deprecated, and PSR-4).
Following that standards it is possible to make use of different tools that handle autoload, without having to code a custom autoloader.
I have to say that WordPress coding standards have different rules for naming files.
So when writing code for WordPress core, developers have to follow WP rules, but when writing custom code it\'s a developer choice, but using PSR standard is easier to use already written tools2.
Global Access, Registry and Service Locator Patterns.
One of the biggest issues when instantiating plugin classes in WordPress, is how to access them from various parts of the code.
WordPress itself uses the global approach: variables are saved in global scope, making them accessible everywhere. Every WP developer types the word global
thousands of times in their career.
This is also the approach I used for the example above, but it is evil.
This answer is already much too long to allow me to further explain why, but reading the first results in the SERP for "global variables evil" is a good starting point.
But how is it possible to avoid global variables?
There are different ways.
Some of the older answers here use the static instance approach.
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self;
}
return self::$instance;
}
It\'s easy and pretty fine, but it forces to implement the pattern for every class we want to access.
Moreover, a lot of times this approach puts on the way to fall in the god class issue, because developers make accessible a main class using this method, and then use it to access all other classes.
I already explained how bad a god class is, so the static instance approach is a good way to go when a plugin only needs to make accessible one or two classes.
This doesn\'t mean that it can be used only for plugins having just a couple of classes, in fact, when the dependency injection principle is used properly, it is possible to create pretty complex applications without the need to make globally accessible a large number of objects.
However, sometimes plugins need to make accessible some classes, and in that case the static instance approach is overwhelming.
Another possible approach is to use the registry pattern.
This is a very simple implementation of it:
namespace GM\\WPSE\\Example;
class Registry {
private $storage = array();
function add( $id, $class ) {
$this->storage[$id] = $class;
}
function get( $id ) {
return array_key_exists( $id, $this->storage ) ? $this->storage[$id] : NULL;
}
}
Using this class it is possible to store objects in the registry object by an id, so having access to a registry it\'s possible to have access to all the objects. Of course when an object is created for the first time it needs to be added to the registry.
Example:
global $registry;
if ( is_null( $registry->get( \'tools\' ) ) ) {
$tools = new GM\\WPSE\\Example\\Tools;
$registry->add( \'tools\', $tools );
}
if ( is_null( $registry->get( \'front\' ) ) ) {
$front_stuff = new GM\\WPSE\\Example\\FrontStuff( $registry->get( \'tools\' ) );
$registry->add( \'front\', front_stuff );
}
add_action( \'wp\', array( $registry->get( \'front\' ), \'wp\' ) );
The example above makes clear that to be useful the registry needs to be globally accessible. A global variable for the sole registry is not very bad, however for non-global purists it is possible to implement the static instance approach for a registry, or maybe a function with a static variable:
function gm_wpse_example_registry() {
static $registry = NULL;
if ( is_null( $registry ) ) {
$registry = new GM\\WPSE\\Example\\Registry;
}
return $registry;
}
The first time the function is called it will instantiate the registry, on subsequent calls it will just return it.
Another WordPress-specific method to make a class globally accessible is returning an object instance from a filter. Something like this:
$registry = new GM\\WPSE\\Example\\Registry;
add_filter( \'gm_wpse_example_registry\', function() use( $registry ) {
return $registry;
} );
After that everywhere the registry is needed:
$registry = apply_filters( \'gm_wpse_example_registry\', NULL );
Another pattern that can be used is the service locator pattern. It\'s similar to the registry pattern, but service locators are passed to various classes using dependency injection.
Main problem with this pattern is that it hides classes dependencies making code harder to maintain and read.
DI Containers
No matter the method used to make registry or service locator globally accessible, objects have to be stored there, and before to be stored they need to be instantiated.
In complex applications, where there are quite a lot classes and many of them have several dependencies, instantiating classes requires a lot of code, so the possibility of bugs increases: code that doesn\'t exist can\'t have bugs.
In last years there appeared some PHP libraries that help PHP developers to easily instantiate and store instances of objects, automatically resolving their dependencies.
This libraries are known as Dependency Injection Containers because they are capable of instantiating classes resolving dependencies and also to store objects and return them when needed, acting similarly to a registry object.
Usually, when using DI containers, developers have to setup the dependencies for every class of the application, and then the first time a class is needed in the code it is instantiated with proper dependencies and the same instance is returned again and again on subsequent requests.
Some DI containers are also capable to automatically discover dependencies without configuration, but using PHP reflection.
Some well known DI Containers are:
and many others.
I want to point out that for simple plugins, that involve only few classes and classes have not many dependencies, probably it doesn\'t worth to use DI containers: the static instance method or a global accessible registry are good solutions, but for complex plugins the benefit of a DI container becomes evident.
Of course, even DI container objects have to be accessible to be used in the application and for that purpose it is possible to use one of the methods seen above, global variable, static instance variable, returning object via filter and so on.
Composer
To use DI container often means using 3rd party code. Nowadays, in PHP, when we need to use an external lib (so not only DI containers, but any code that isn\'t part of the application), simply downloading it and putting it in our application folder is not considered a good practice. Even if we are the authors of that other piece of code.
Decoupling an application code from external dependencies is sign of better organization, better reliability and better sanity of the code.
Composer, is the de-facto standard in PHP community to manage PHP dependencies. Far away to be mainstream in WP community as well, it\'s a tool that every PHP and WordPress developer should at least know, if not use.
This answer is already book-sized to allow further discussion, and also discussing Composer here is probably off topic, it was only mentioned for sake of completeness.
For more information visit the Composer site and it\'s also worth giving a read to this minisite curated by @Rarst.
1 PSR are PHP standards rules released by the PHP Framework Interop Group
2 Composer (a library that will be mentioned in this answer) among other things also contains an autoloader utility.