Why Singletons have no use in PHP
I am pretty sure everyone working professionally or semi-professionally has heard, seen or worked with a Singleton before in one way or the other. For those of you who never heard of it, let me reiterate the purpose of that Design Pattern:
- Make sure there can be only one instance of a class at any time.
- Provide global access to that single instance from anywhere within your application.
You’ll often find Singletons as wrappers around database adapters to limit the amount of connections. Another popular use is to make Front Controllers or a Registry into Singletons.
Unlike some other patterns, creating a Singleton is easy.
- Add a static
getInstance()method to allow global access.
- Call the Singleton’s constructor on first call
- Assign the newly created instance to the static
$instanceon subsequent calls.
__construct()private to prevent direct instantiation from outside.
__clone()private to prevent cloning from outside.
__wakeup()private to prevent deserializing from outside.
There used to be a similar sample implementation in the PHP Manual as well (now removed). Variations of that implementation exist in other languages. In PHP this one is the dominant variant though, mainly due to language constraints.
However, despite it’s apparent usefulness and wide adoption, the Singleton is also controversial. Many developers see it as an AntiPattern nowadays and I tend to agree with them.
Singletons are not unique snowflakes
In languages where objects live in an application server, Singletons can be used to keep memory usage low. Instead of creating two objects, you reference an existing instance from the globally shared application memory. In PHP there is no such application memory. A Singleton created in one Request lives for exactly that request. A Singleton created in another Request done at the same time will still be a completely different instance. And it will occupy it’s own memory. Those instances are not linked to each other. They are completely isolated, because PHP is a Shared-Nothing architecture. You do not have one single unique instance, but many similar instances in parallel processes. Thus, one of the two main purposes of a Singleton is not applicable.
Don’t construct twice, it’s all right
Advocates of the Singleton in PHP often argue it’s still useful to be able to limit an instance within a single request. The aforementioned database classes being the most prominent example. But the much easier solution would be simply not to instantiate a second instance. If anyone can make sure there is just one instance, it’s the developer. If you need to have the same instance in many classes, use Dependency Injection. Just create one, inject everywhere. That will also save you the hassle of deconstructing your Singleton once you notice you need a second instance of it all of a sudden.
Another example where Singletons are often applied but don’t make sense is classes like FrontControllers. While conceptually it makes sense to say “There may be only one FrontController”, it is superfluous to ensure it from an architectural viewpoint. A FrontController is usually instantiated only once in your application’s control flow anyway. If you don’t write a new Foo; anywhere else, you already made sure there is just one instance. So you ain’t gonna need the Singleton here. Don’t express concepts in your code that are never used.
Don’t shoot yourself in the foot
The Singleton’s other purpose (to have a global access point to the instance) is undesirable in PHP. The desire for that usually stems from having an architecture where objects pull in their dependencies. Like any globals and statics, the Singleton’s
getInstance() method creates coupling to the global scope. This makes Unit-Testing harder. There is ways to mitigate this, but in general, the cost to mitigate is higher than to simply avoid the Singleton in favor of Dependency Injection. This is especially true in those situations, where the Singleton is applied but never instantiated twice anyway.
When working with PHP, Singletons cannot live up to their full potential due to PHP’s Shared Nothing architecture. They are also introducing a number of undesirable disadvantages that will make your application less maintainable and harder to change. And to add another sure sign that you should be wary of the Singleton: even Erich Gamma, one of the pattern’s inventors, doubts the Singleton nowadays:
I’m in favor of dropping Singleton. Its use is almost always a design smell
Hopefully this is enough to make you reconsider next time you think about using a Singleton. Should you still have trouble deciding, use the following cheatsheet: