The Singleton Design Pattern is something that I’ve talked about before in previous articles.
As Wikipedia so eloquently defines it:
In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.
If you’ve done any work with object-oriented programming and familiar design patterns, then it’s likely that you’ve come across it (if you haven’t used it).
Depending on who you ask, the singleton design pattern may be treated as an anti-pattern, like some weird use of a “poor man’s namespace,” or one of the many other negative views of it.
Though these perspectives aren’t necessarily wrong, there are times where it’s okay to use it.
The Singleton Design Pattern
To me, the singleton design pattern isn’t problematic in and of itself. If that were the case, I don’t believe that it would have ever become one of the patterns as documented by the Gang of Four.
It’s the way that it’s used (or misused, to be more precise) that becomes a problem. For example, if your goal is to use object-oriented programming but you use the singleton design pattern more often than not, then you’re not so much leveraging the advantages of object-oriented programming.
An Example of The Pattern
Ultimately, I’m going to walk through an example of how the pattern can be used as [an admittedly weak] dependency injection container (which I’ll cover in more detail later in this article and the second and third part of this series).
But before I do that, I think it’s worth taking a look at what the pattern looks like and talk about some of the key points so that everyone reading this is on the same page.
And before reviewing the code, note that there are minor variations of the pattern. What I’ve included below is my preferred way of setting it up, though others have their preferences, as well.
I’d like the think the comments are clear but I know that some who read this are coming from other backgrounds or are new to object-oriented programming, so I want to highlight a few things in the code that are worth noting:
- Because this is an object-oriented pattern, all of the functionality exists in a class. If you’re familiar with namespaces, this can also be placed in a namespace (and often should be if you’re managing your code regarding packages or modularity).
- The only property the class maintains is a reference to an instance of the class. Normally, these are not
staticbut because of the nature of the pattern, this property is. Note that
staticindicates the data isn’t related to multiple instances of an object. Since the singleton pattern is, by definition, limited to a single instance, the reference to the object should be marked as such.
- The constructor is marked as
privatebecause the pattern dictates there should only be a single instance of the object (which is counterintuitive, I know). It’s marked as
privateso no external classes can instantiate it. Instead, only internal methods can do so.
- The only
publicfunction that’s available is that of
get_instancewhich looks to see if the property [discussed above] is referencing a value (which should be an instance of the class). If it’s not, then, it sets it. After that, it will return a reference to the instance.
Depending on your level of experience, you may hear static variables are terrible, that the singleton pattern should never be used, that the design pattern is an anti-pattern and all of that.
All of that to say, there is no consensus. Whatever the case, the pattern is used, and it’s worth understanding so you can work with it even if you hate it or plan never to use it in your work.
If you’re working with WordPress, the odds that you’ve seen anything around dependency injection containers, and the like are pretty small. Not unheard of, but small.
And though the basics of the pattern are above, it doesn’t really relate to dependency injection nor does it relate to and how I think it can be used as a dependency injection container (at least in an intermediate stage of development).
To be clear, I recognize that this is not the final form a container should take nor does it feature any type of functionality that a container normally maintains. But remember the goal of this is to show the pattern and to show one way that it can be used when you have limited time or resources when working on a solution.
That is, you need interstitial functionality and that’s what I’m hoping to achieve with the next post.