Singletons are one of many design patterns that developers employ to solve common problems. In this three-part series, we will look at what they are, when to use them, some different types of singletons, and how to implement them yourself.
This post is at an intermediate level as it is quite conceptual but needs very little code knowledge. Although this post has examples in PHP, the concepts it describes apply to all object-oriented programming languages.
The next post in this series is available here: Singletons: Two ways about it.
What Are Singletons
The Problem
In any software system, we need to store data. Namely program state, in variables. For important pieces of data, we might want them to to be accessible to many different parts of the system, at many different times. Typically the simple answer to this is to make some global variables.
Global variables get a lot of stick online, and one of the prevalent reasons is to do with their structure.
Say you want to store quite a bit of data about the current web request, for example:
- The time the connection was made
- The duration of the request so far
- The I.P. address of the requester
- An array of sanitised POST and GET parameters
- E.T.C.
You are either going to end up with a lot of global primitives, which will get cluttered very fast, or one global object. However, with a global object, if a developer writes:
$request_info = new RequestInfo();
instead of
global $request_info;
They are going to end up with a blank copy of your RequestInfo Object!
Enter Singletons
Wouldn’t it be nice if we could have a class, like our RequestInfo, but there can only ever be one of them. No matter how hard the pesky developers try, they will always end up with the original RequestInfo that you created for them.
That’s what a singleton is, it’s an object, that you can only ever have one of.
Creating a class that can only be instantiated once sounds like the opposite of what a class is meant for, but Singletons persist as an elegant way of storing global (or sometimes even scope specific) data, bundled into a convenient package.
Yay, let’s use Singletons for EVERYTHING
Is certainly what I said when I first heard about them. But you don’t want to become the fabled ‘man with a hammer‘ to which everything is a nail.
Let’s think about a couple of WordPress global variables, and decide whether they would be better as Singletons.
The Global $post Object
The global post object may seem like a great candidate at first:
- It’s global
- It’s an object
However, it’s very quick to see why we would not want to make WP_Post a Singleton:
global $post;
$related_post_id = get_post_meta( $post->ID, ‘related_post’, true );
$related_post = get_post( $related_post_id );
The above snippet simply loads a post ID from the global post’s meta and then gets a post object for that related post ID. In three lines of code, we can see that it’s very important to be able to create more than one WP_Post object.
The Global $wpdb Object
The $wpdb
object is also global, and it’s also an object. So let’s get thinking: Is there ever a reason to have two $wpdb
; objects?
The answer is a pretty resounding no! The $wpdb
object is a wrapper for PHP access to the WordPress Database. In this case, the global object is actually less about storing data, and more about providing an API to access some external service. In this instance, a MySQL server.
The be all and end all, however, can be found in bold in the codex entry for $wpdb
:
Warning: Methods in the
wpdb()
class should not be called directly. Use the global$wpdb
object instead!
Pretty succinct: Don’t make one yourself, always use the global $wpdb.
This makes $wpdb a great candidate for being a Singleton, so, why isn’t it?
Probably to maintain backwards compatibility. Which is a good enough reason as any.
Ok, let’s use singletons sometimes.
Yes, let’s.
If you have a global data structure that you really don’t want developers duplicating. Whether it be because that data structure contains specific values that the developer might want. Or because it abstracts some service access behind an API, and having more than one would be nonsensical. Singletons are a great way or making sure you can never have two instances of the same class.
Next up, learn about how the two common ways of implementing singletons in: Singletons: Two ways about it.