Dependency injection for WordPress plugins
In my last post, I criticized the use of the Singleton pattern in WordPress, and presented dependency injection as an alternative. But I presented it in only a very general way. Eric Mann provided detailed write-ups of how to use the Singleton pattern, so – to be fair – I should do the same with dependency injection (I don’t want to be a drive-by critic). See my last post for a general overview (and my slides below from my WordCamp Nashville presentation for a much deeper dive).
If your plugin is fairly simple – say a few hundreds lines of code – you don’t need to bother with dependency injection, or any other fancy design patterns. But when you get to the point where you have dozens of functions or methods, you’re feeling tempted to copy and paste code, and a little change here breaks something there, it’s time to get organized. The key to maintainable, flexible code entails understanding several concepts, but there are two which I believe are foundational:
- Writing small classes that do one thing (the single responsibility principle). I’ve written about this in detail in a previous post: WordPress plugins: does size matter? Applying the Single Responsiblity Principle
- Having your objects interact with each other through the use of dependency injection
In it’s simplest form, this means passing objects directly to each other, so they can make use each other’s functionality. Here’s a simple example of a button that can turn on and turn off a lamp:
class Button { private $lamp; public function __construct(Lamp $lamp) { $this->lamp = $lamp; } public function poll() { if (/* some condition */) { $this->lamp->turnOn(); } //... } }
This separation of concerns make it possible for a lamp to be passed to some other class to be used for other purposes (perhaps an electrical outlet), and it also allows for unit testing (a concept I won’t get into here). But we can do better. This button only works with lamps. What if we want to use it to control a motor too? We can create an SwitchableDevice interface and have our Motor class and our Lamp class implement it. Now the button can control anything that implements the SwitchableDevice interface:
class Button { private $switchableDevice; public function __construct(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice; } public function poll() { if (/* some condition */) { $this->switchableDevice->turnOn(); } //... } }
This may seem like a trite example, but the concept is very powerful. My Post to Post Links II error: No post found with slug "shashin-wordpress-plugin" plugin currently supports showing images and vidoes from Picasa, Youtube, and Twitpic. I can add support for any other photo or video service by creating a new subclass. For example, I could create a Flickr subclass that contains the logic particular to dealing with Flickr photos, just drop it into Shashin, and I’m done. I don’t have to monkey with any of the pre-existing code at all. The other objects in Shashin – for storing photo data, rendering the image tags, etc – don’t know and don’t care where the photo came from. As long as my Flickr subclass follows the same rules as the other subclasses, they know exactly what to do with it when they receive a Flickr photo object.
So what happens when you have objects that depend on other objects, that depend on other objects, and so on? You create an injection container to manage the dependencies, so that each individual object only needs to know about its immediate collaborators (that is, they know their friends, but they don’t get entangled with their friends’ friends). Injection containers allow you to follow the Law of Demeter (which I’ve written about previously here: Talking to strangers causes train wrecks). Here’s a simple example of what one looks like, from my Shashin plugin:
class ShashinContainer { // … public function getPhotoRefData() { if (!isset($this->photoRefData)) { $this->photoRefData = new ShashinPhotoRefData(); } return $this->photoRefData; } public function getClonablePhoto() { if (!isset($this->clonablePhoto)) { $this->getPhotoRefData(); $this->clonablePhoto = new ShashinPhoto($this->photoRefData); } return $this->clonablePhoto; } //... }
If another class needs a clonablePhoto, it can ask for it from the container, and not have to worry about what dependencies the clonablePhoto has. Again, this is very powerful: if you get a new business requirement that entails a major structural change, you can handle it without having to sift through your entire codebase. You can make the changes to the classes that are directly affected, with a minimal ripple effect on the rest of your code.
This illustrates more specifically how dependency injection can be used as an alternative to the Singelton pattern, for instantiating objects only once when you don’t need more than one. In my injection container example, you’ll see the objects are stored as properties of the container, and are never created more than one time. The limitation is that an unknowing programmer could bypass the container and create more instances of the objects by directly calling “new” on its class. This limitation is something you need to weigh against the various shortcomings of using Singletons (see my previous post).
Mike Schinkel uses the Singleton pattern for another purpose – to avoid having the instance of a plugin’s class in the global namespace. I’m not sure how much this solution helps with the overall problem: other developers trying to deal with your plugin still need to know how to find it – they’re just looking for something else now, and have to learn this particular Singleton implementation (however I have not yet had to deal with this problem in my own work, so I may be overlooking some aspect). Based on the comments on his post, it seems like the main frustration developers have is figuring out where the hooks and filters are in someone else’s heavily object oriented plugin (where the logic can get spread out). This strikes me more as a code organization problem, not a variable scoping problem. In my plugins, I put almost all my hooks and filters in one place. This is the main method for my Shashin plugin:
public function run() { add_action('admin_init', array($this, 'runtimeUpgrade')); add_action('admin_menu', array($this, 'initToolsMenu')); add_action('admin_menu', array($this, 'initSettingsMenu')); add_action('wp_enqueue_scripts', array($this, 'displayPublicHeadTags')); add_shortcode('shashin', array($this, 'handleShortcode')); add_action('wp_ajax_nopriv_displayAlbumPhotos', array($this, 'ajaxDisplayAlbumPhotos')); add_action('wp_ajax_displayAlbumPhotos', array($this, 'ajaxDisplayAlbumPhotos')); add_filter('media_upload_tabs', array($this, 'addMediaMenuTabs')); // ... and so on - there are 8 more... }
This makes things pretty easy to find. It’s through the method calls listed here that Shashin’s other objects get instantiated. There’s really no need to put these calls anywhere else. They are all stand-alone actions in the WordPress environment, and kick off everything else that happens in my plugin.
If you’ve gotten this far and still want more, here are my slides from my WordCamp Nashville presentation on dependency injection, which go into more detail on the examples I used above. There are also more advanced examples, and an overview of class autoloading:
Actually that's a misunderstanding of why I advocate the Singleton pattern.
Yes, the avoidance of another variable in the global namespace is a happy side-effect but it's not the main benefit of using a Singleton for a WordPress plugin; the main benefit is as a defacto-namespace for the methods used for the plugin's hooks. By "namespacing" them it keeps their names out of the global namespace too which also means you can use shorter method likes, like
init()
instead of global function names likemy_plugin_name_init()
. This latter makes it easier to follow a "hook name equals method name" method whenever possible.I could have advocated for the use of real PHP namespaces instead but since PHP namespaces require PHP 5.3 and WordPress still supports PHP 5.2.4 I argue that most plugins should not require 5.3 and thus not use PHP namespaces.
Another benefit of using a Singleton for a plugin's main class is that it allows for convenient structuring of data and code; rather than having more variables to keep track of data such as the settings array that many plugins will use, that data can be maintained in an instance property. The alternate is more public variables, ugh, or having to craft complex parameters to pass the data around between different functions; double ugh!
On the other hand instead of Singletons I could have recommended usings defacto-static classes being abstract classes with only static variables and methods, and that was the approach I chose originally. However after using that architecture for a while I discovered it was an architectural dead-end:
PHP 5.2.x does not have
__callStatic()
so you have no dynamic methods in "static" classes for PHP 5.2.4, and no version of PHP has__getStatic()
or__setStatic()
methods so you have no flexibility at all for dynamic properties for "static" classes whereas that flexibility is critical when you get into more advanced WordPress plugin code architectures.PHP 5.2.4 also lacks of a
get_called_class()
function which is important for using static base classes designed to be extended/inherited from.Debuggers like Zend and XDEBUG will automatically display instance vars in a "watch" window but not static variables which makes debugging with defacto-static classes a real pain in the a**.
And frankly the PHP syntax for accessing a static variable is ugly:
My_Plugin_Class::$my_static_var
🙂So my recommendations for use of Singletons is frankly because WordPress still supports 5.2.4 and PHP did not support namespaces nor class extensibility early enough, and in the case of
__getStatic()
and__setStatic()
that PHP doesn't support it at all. In a perfect world I'd advocate static classes using namespaces, but that's simply not possible with today's reality.It's also extremely important to point out that I'm only recommending Singletons for very select use-cases with those being to encapsulate the methods used for hooks. That means, typically, that a simple plugin would only have one Singleton class, i.e. the main plugin class whereas a more complex plugin might have three (3), one each used for:
Global hooks, i.e. all of WordPress,
Hooks for the WordPress admin, and
Hooks for AJAX-triggered methods.
Finally I think that Singleton patterns have been branded as "bad" for most use-cases by some influential programmers and thus any mention of it evokes a witch hunt by some many other programmers. While some developers rightly criticize the use of Singletons for inappropriate use-cases it seems most others just pile on dogma when they see the word "Singleton" mentioned. I often wonder if those people even know what about Singletons make them bad; I suspect most do not.
As an aside I only chose to apply the Singleton label to the architecture I was using after I had started using it because I wanted to more easily be able to communicate it. I did not realize it would reflexively trigger a negative reaction in so many people. (Ironically most of the developers who complained about it the loudest on Hacker News were not WordPress plugin developers and they objected to Singleton's use without even knowing the use-case. doh!)
I really don't think that code organization is relevant here (although I organize my code in a similar manner except that I match method names with hook names whenever possible.) Having your hooks configured in one place does nothing to help the user of your plugin know how to access
$this
externally. For that you need a static accessor method.Further you don't want people having to read through your plugin code to be able to extend it; there should be a standard pattern they just know will be there, or at least have documentation for how to do with in the plugin's
readme.txt
. I dealt with the issue in the post you linked by proposing WordPress plugin authors get into the pattern of offering a staticthis()
method for Singletons; that is pretty straight forward to me although knowing how headstrong developers can be about doing things their own way I don't hold high hopes it will be adopted broadly.Best would be to have the WordPress core team promote a standard approach although for some reason this is the type of thing they ever seem to want to provide guidance on; why, I don't know.
As another aside Tom McFarlin recently stated in his comments on this post that he thinks "'Dependency Injection' is a dumb term", and I could not agree more. I also think that the classic computer science examples for dependency injection are not a best practice for WordPress because we can do it with hooks that are not available in the languages typically used to illustrate DI. Tom and I had a great dialog about DI in that thread if you want to read. FWIW.
Hi Mike – thanks for the detailed response, and sorry for the delay with this reply. I completely understand why you and others are using the Singleton pattern in the context of WordPress plugins. I understand that it gives you a way to deal with the global state that WordPress forces you to deal with. And I understand that what I’m talking about with DI doesn’t solve all those problems. But I felt DI was being dismissed with strawman arguments that really did not at all fairly represent how effective it can be, especially for organizing the internal logic of a complex plugin (and it’s certainly not any more conceptually complex than the practices I’m seeing evolve around Singletons in WordPress).
What made me want to object so vocally is that at the end of the day, nothing you’re saying changes the fundamental problems with the Singleton pattern, whether it’s used in WordPress or anywhere else (see the references section of the Singleton Wikipedia page, especially the Clean Code talk). It was a popular pattern a long time ago, and fell out of favor as so many problems with it were discovered.
As someone who develops in both WordPress and other environments, I find it frustrating that WordPress is evolving a set of practices that set it apart from what is going on in the mainstream programming community (whether you’re working Ruby on Rails, Doctrine in PHP, or other frameworks, you can design robust apps following the SOLID principles, but there are obstacles to applying them in WordPress). I’ve interviewed and hired pretty good WordPress developers for jobs that aren’t WordPress, and working in WordPress has given them a set of programming habits they need to unlearn to be successful in other modern development environments.
I realize what I’m talking about here doesn’t solve all the real and immediate needs that have led you to adopt Singletons. But I am trying to spark a conversation about whether WordPress should keep going down the road its on – one that will divide it more and more from the rest of the programming community. WordPress’ API can’t be changed at this point (i.e. global variables and hooks are here to stay). but they could all be managed through wrappers over time, with an OO framework under the hood. Then we could have the best of both worlds: an environment that’s still easy for hacking (which is a big part of the reason WordPress has become so successful), and under the hood have an environment which can more readily support development work using widely accepted OO design principles. This would also allow for more cross-pollination of ideas and practices from the mainstream programming community.
Glad you are tackling better practices for WordPress developers!
Your posts and slides are well done, so thank you!
I just finished writing an Elasticsearch plugin that makes extensive use of DI and SR and I would not have been able to keep is understanable for myself or other developers that will inherit my work.
Cameron
Thanks for the kind words. If your plugin is available online, I’d like to see what you’ve done.
Hey Mike, thanks for a great post and slide. This is an old post but still valuable. I have a question: while creating a DI container, what is the best way to get access to that container in other places?
Thanks for the comment! It’s been a long time – I mainly work in Ruby now – but here’s some example code of mine calling a container.
Thanks a lot!