Essay

July 8, 2017 · 19 min · Updated July 10, 2017

Singletons And Shared Instances

Every once in a while, when discussing software design with fellow developers, the topic of Singletons comes up, especially in the context of WordPress development....

Every once in a while, when discussing software design with fellow developers, the topic of Singletons comes up, especially in the context of WordPress development. Often times, I try to explain why these should be avoided, even though they are recognized as being a “standard pattern”.

In this article, I try to go over the reasoning of why the Singleton should never be used in your code, and what alternative approaches you can use instead to solve the same problems.

What is a Singleton?

The Singleton is a software design pattern that has been described in the book Design Patterns: Elements of Reusable Object-Oriented Software by “the Gang of Four”, the reference that effectively started the talk about Design Patterns as a software engineering tool.

The basic principle is that you want to ensure there can only ever be a single instance of a given class, and you provide a global point of access for it.

This is really easy to explain and understand, and for most people, the Singleton is the entry drug into the world of Design Patterns, making it the single most popular pattern.

So, given its popularity, and given the fact it is part of the reference book and was amongst the first patterns to be described and standardized, how comes that some developers decry it as an “anti-pattern”? Can it really be that bad?

Yes.

Yes, it can.

But Singletons are useful and necessary!

I notice that a lot of people confuse two related concepts, and when they say they need a Singleton, they actually mean to say they need to share a same instance of an object across different instantiations. In general, when you instantiate a class, you create a new instance of that class. But for some objects, you want to always use the same, shared instance of that object, no matter where it is being used.

But the Singleton is not the proper solution for this.

The confusion is caused by the fact that a Singleton actually combines two responsibilities in one object. Imagine having a Singleton that is being used to establish a connection to the database. Let’s call it (very creatively) DatabaseConnection. The Singleton now has the following two main responsibilities:

  1. Manage the database connection.
  2. Manage the instantiations of the DatabaseConnection.

Responsibility 2. is what makes people pick the Singleton, but this task should actually be the responsibility of a different object.

The problem with a Singleton is not that it is shared, but that it enforces its own instantiation.

There’s nothing wrong with using a shared instance. But the object you want to share is not the place to put that restriction into.

I’ll show some alternative approaches of how to handle this later in the article. But first, I want to discuss what types of problems the Singleton will cause.

Problems with the Singleton Pattern

Singleton vs SOLID

First of all, and this might seem to be more of a theoretical and puristic issue than a real problem at first, the Singleton design pattern breaks most of the SOLID principles.

  • S stands for "Single Responsibility Principle". It should be obvious that the Singleton pattern goes against this principle, as already described above.
  • O stands for "Open/Closed Principle", meaning that objects should be open for extension but closed for modification. The Singleton breaks this principle because it controls the point of access, and will only ever return itself, not an extension.
  • L stands for "Liskov Substitution Principle", meaning that objects should be replaceable by instances of their subtypes without needing changes to the consuming code. This obviously does not work out for a Singleton, as the simple fact of having multiple differing versions of an object causes it to not be a Singleton anymore.
  • I stands for "Interface Segregation Principle", meaning that you should prefer many client-specific interfaces over one general-purpose one. This is the only principle that the Singleton does not directly break, but only because the Singleton does not allow for an interface to begin with.
  • D stands for "Dependency Inversion Principle", stating that you should depend on abstractions, not concretions. Once again, the Singleton breaks this principle, because you can only ever depend on the very concrete Singleton instance.

The Singleton pattern breaks four out of five SOLID principles! It would probably even want to break the fifth as well, if only it was able to have interfaces in the first place…

The Singleton pattern breaks four out of five SOLID principles!

It is easy to say that your code does not work or break because of some random theoretical principles. And although my personal experience has shown time and time again that these principles are amongst the most valuable and enduring guidelines you can adhere to in terms of software design, I acknowledge that just stating this as a “fact” will probably not convince a lot of people. We should look at the impact the Singleton pattern has for your immediate practical reality.

Singleton in practical use

Here are the more practical drawbacks and issues that a Singleton brings about:

  • You cannot have arguments passed to/injected into the constructor. As the constructor is only actually executed by the first call that hits the Singleton, and you cannot know in advance, which of the consuming code will be the first one to hit the Singleton, all consuming code would need to have the exact same set of arguments to pass to the constructor, which is both not practically feasible in most cases, and rather pointless to begin with. As a result, the Singleton renders the main mechanism of instantiation in OOP languages useless.
  • You cannot mock the Singleton away when testing other components that make use of it. This makes proper unit tests practically impossible, because you never have a clear isolation of the code you want to test. This problem is not even caused by the actual logic you want to test, but rather by the arbitrary instantiation restriction you wrapped it into.
  • As the Singleton is a globally accessible construct that is always shared across your entire codebase, it defeats any efforts for encapsulation, causing the exact same problems as global variables do. This means that whatever you try to do to get the Singleton isolated in an encapsulated part of your code, any other external code can cause side effects and produce bugs through this Singleton. Without proper encapsulation, the very principles of object-oriented programming are diluted.
  • If you ever have your site/app grow to the point where your DatabaseConnection Singleton suddenly needs to allow for a second, different database connection nevertheless, you're in a world of trouble. Your very architecture needs to be revised, and will probably cause large portions of your code to need a complete rewrite.
  • All of the tests you write that make use of your Singleton in a direct or indirect way cannot be properly reset from one test to the next. They always carry over state through the Singleton, which can produce weird behavior where your tests depend on the order they are run in or obfuscate actual bugs because of left-over state.
  • They only enforce their singular instantation for the current process space that is valid for the static scope. This means that you'll run into issues with multi-threading, with multiple processes or with distributed execution. This should hint to the possibility that they are just a faulty concept that simply breaks down as soon as you work in a distributed system.

Alternatives to using a Singleton

I don’t want to be the person that decries everything as bad but then fails to provide viable alternatives or preferable approaches. Although I do think that you need to consider your overall architectural design to decide how best to avoid Singletons in the first place, I can think of a few common use cases in WordPress where the Singleton can easily be replaced with a mechanism that meets all requirements while avoiding most or all of the drawbacks. But before describing these, I’d like to point out why all of them are only a compromise.

There is an actual “ideal structure” for dealing with the construction of an app. The theoretical best case is one single instantiation call in the bootstrap code that builds the entire dependency tree of the complete app from the top down. This would work along the lines of this example:

  1. Instantiate App (needs Config, Database, Controller).
  2. Instantiate Config to inject into App.
  3. Instantiate Database to inject into App.
  4. Instantiate Controller to inject into App (needs Router, Views).
  5. Instantiate Router to inject into Controller (needs HTTPMiddleware).
  6. ...

With a single call, the entire application stack would be built from the top down, injecting the dependencies as needed. The goals with such an approach:

  • Every object has an exact list of dependencies it needs, and should only make use of these dependencies. When something breaks, you can easily isolate the responsible code.
  • No tight coupling between any of the objects, all objects rely on interfaces only while using whatever implementations will be injected.
  • No global state. Every individual subtree in the above hierarchy would be properly isolated from the rest, without the developers being able to introduce bugs into module B while making changes to module A.

The ideal app construction is a single instantiation call that builds the entire dependency tree.

However, as good as this might sound, it is just not possible with WordPress code. WordPress does not provide any centralized container or injection mechanism, and each of the plugins/themes are loaded in an isolated way.

Keep this in mind while we discuss the possible approaches below. The ideal solution, having the entire WordPress stack be instantiated through one centralized injector, is currently out of reach as it would need to be supported by the WordPress Core. All of the approaches below will share some of the same drawbacks in differing degrees, like the fact that they hide dependencies by accessing them directly from within the logic instead of having them be injected.

Singleton code

Here is the example code for the Singleton approach that we will use as a base to compare the other approaches to:

// Singleton.
final class DatabaseConnection {

   private static $instance;

   private function __construct() {}

   // Call to get a hold of the one true instance.
   public static function get_instance() {
      if ( ! isset( self::$instance ) ) {
         self::$instance = new self();
      }

      return self::$instance;
   }

   // Actual logic code mixed in with the instantiation mechanism.
   public function query( ...$args ) {
      // Execute query and return results.
   }
}

// Consuming code.
$database = DatabaseConnection::get_instance();
$result   = $database->query( $query );

I didn’t include all of the implementation details that Singletons are often loaded with, as they don’t add anything to the theoretical discussion.

Using Factories

In most cases, the easiest way to defuse your problems with Singletons is to use the Factory pattern instead. A Factory is an object that has the instantiation of objects as its single responsibility. Instead of having a DatabaseConnectionManager that takes care of its own instantiation via a get_instance() method, you’ll have a DatabaseConnectionFactory that can hand out instances of a DatabaseConnection object. In general, the Factory would always hand out new instances of a requested object. But it can decide, based on the requested object and the context, whether to hand out new instances or to always share one instance only.

Regarding the naming, you might think that this looks more like Java code than PHP code, so feel free to stray away from a too strict (and thus lazy) naming convention and name the Factory in a more straightforward and creative way.

Example code for the Factory approach:

// Factory.
final class Database {

   public function get_connection(): DatabaseConnection {
      static $connection = null;

      if ( null === $connection ) {
         // You can have arbitrary logic in here to decide what
         // implementation to use.
         $connection = new MySQLDatabaseConnection();
      }

      return $connection;
   }
}

// Interface, so that we can deal with multiple implementations and properly
// mock for testing.
interface DatabaseConnection {

   public function query( ...$args );
}

// The implementation we're currently using.
final class MySQLDatabaseConnection implements DatabaseConnection {

   public function query( ...$args ) {
      // Execute query and return results.
   }
}

// Consuming code.
$database = ( new Database )->get_connection();
$result   = $database->query( $query );

You can see that the consuming code is not more difficult or verbose to write, there’s only a slight nuance to it. We’ve opted to call the Factory Database instead of DatabaseConnectionFactory, as this is part of the API we’re providing, and we always should strive to hit the right balance between logical precision and elegant consiceness.

The Factory version above gets rid of pretty much all of the drawbacks we’ve been identifying before, with a small exception:

  • Although we've removed the tight coupling to the DatabaseConnection object, we've introduced a tight coupling to the new Factory instead. This is not problematic, as the Factory is a pure abstraction, and there's a very low probability that we need to move away from the actual concept of "instantiation" at one point. If that should happen, the entire paradigm of OOP probably needs to be revised.

You’ll probably start wondering now about the fact that we are not able to enforce a single instantiation anymore. Although we always hand out a shared instance of a DatabaseConnection implementation, anyone can still just do a new MySQLDatabaseConnection() and thus get access to an additional instance. Yes, that is correct, and that is actually one of the goals of getting away from the Singleton pattern. It is good to have conventions about always sharing an instance of an object. But enforcing something like this does not provide additional real-world benefits, while making basic requirements like unit testing impossible.

Using Static Proxies

A Static Proxy is another design pattern that can be used to get rid of Singletons. It introduces more tight coupling than the Factory does, but this coupling is still only tied to an abstraction, not a concrete implementation. The basic principle is that you have a static mapping of the interface, and these static calls are being transparently forwarded to a concrete implementation behind the scenes. As such, there’s no direct coupling to the actual implementation, and the Static Proxy is free to decide in what ways to pick the actual implementation to use.

// Static Proxy.
final class Database {

   public static function get_connection(): DatabaseConnection {
      static $connection = null;

      if ( null === $connection ) {
         // You can have arbitrary logic in here to decide what
         // implementation to use.
         $connection = new MySQLDatabaseConnection();
      }

      return $connection;
   }

   public static function query( ...$args ) {
      // Forward call to actual implementation.
      self::get_connection()->query( ...$args );
   }
}

// Interface, so that we can deal with multiple implementations and properly
// mock for testing.
interface DatabaseConnection {

   public function query( ...$args );
}

// The implementation we're currently using.
final class MySQLDatabaseConnection implements DatabaseConnection {

   public function query( ...$args ) {
      // Execute query and return results.
   }
}

// Consuming code.
$result = Database::query( $query );

As we can see in the consuming code example, the Static Proxy creates a very short and clear API, with the drawback being that it tightly couples the code to its class signature. If used in the right places, this should not be a real problem, as the tight coupling is still to an abstraction you can directly control, and not to a concrete implementation. You are still able to swap out the specific database code with a different one as you see fit, and our actual implementation is still a completely normal object that can be easily tested.

Using the WordPress Plugin API

The WordPress Plugin API can also be used to get rid of Singletons, when they are being used for their capability of providing global access across plugins. This is a mostly clean solution within the constraints of WordPress, with the added caveat that it ties the entire infrastructure and architecture of your code to the WordPress Plugin API. Don’t use this if you intend to reuse your code with different frameworks.

// Interface, so that we can deal with multiple implementations and properly
// mock for testing.
interface DatabaseConnection {

   const FILTER = 'get_database_connection';

   public function query( ...$args );
}

// The implementation we're currently using.
class MySQLDatabaseConnection implements DatabaseConnection {

   public function query( ...$args ) {
      // Execute query and return results.
   }
}

// Initialization code.
$database = new MySQLDatabaseConnection();
add_filter( DatabaseConnection::FILTER, function () use ( $database ) {
   return $database;
} );

// Consuming code.
$database = apply_filters( DatabaseConnection::FILTER );
$result   = $database->query( $query );

One of the main compromises with this code is that your architecture is directly tied to the WordPress Plugin API. If you ever plan to provide your plugin functionality for Drupal sites as well, you’re facing a complete rewrite.

Another potential issue is that you’re now relying on the timing of the WordPress hooks. This can introduce timing-related bugs, which are often hard to replicate and debug.

Using a Service Locator

A Service Locator is one form of an Inversion of Control Container. You’ll find several references online outing it as an anti-pattern. This is true to some degree, but as we had already discussed above, all of the recommendations here have to be considered as compromises only.

The Service Locator is a container that gives you access to Services that were implemented elsewhere. The container itself is mostly just a collection of instances mapped to identifiers. More elaborate Service Locator implementations might add features like lazy instantiation or proxy generation to the mix.

// Container interface so that we can swap out the Service Locator
// implementation.
interface Container {

   public function has( string $key ): bool;

   public function get( string $key );
}

// Basic implementation of a Service Locator.
class ServiceLocator implements Container {

   protected $services = [];

   public function has( string $key ): bool {
      return array_key_exists( $key, $this->services );
   }

   public function get( string $key ) {
      $service = $this->services[ $key ];
      if ( is_callable( $service ) ) {
         $service = $service();
      }

      return $service;
   }

   public function add( string $key, callable $service ) {
      $this->services[ $key ] = $service;
   }
}

// Interface, so that we can deal with multiple implementations and properly
// mock for testing.
interface DatabaseConnection {

   public function query( ...$args );
}

// The implementation we're currently using.
class MySQLDatabaseConnection implements DatabaseConnection {

   public function query( ...$args ) {
      // Execute query and return results.
   }
}

// Initialization code.
$services = new ServiceLocator();
$services->add( 'Database', function () {
   return new MySQLDatabaseConnection();
} );

// Consuming code.
$result = $services->get( 'Database' )->query( $query );

As you might have guessed in the above example, there’s still the problem of getting a hold of the reference to the $services instance. This can be solved by combining it with any of the previous three methods.

  • Using a Factory:
    $result = ( new ServiceLocator() )->get( 'Database' )->query( $query );
  • Using a Static Proxy:
    $result = Services::get( 'Database' )->query( $query );
  • Using the WordPress Plugin API:
    $services = apply_filters( 'get_service_locator' );
    $result   = $services->get( 'Database' )->query( $query );

This leaves us now with the question of whether we should really use the “anti-pattern” Service Locator to replace the “anti-pattern” Singleton… The problem with the Service Locator is that it “hides” dependencies. To explain what this means, you need to think about a code base that actually uses proper constructor injection throughout. In such a codebase, a quick look at the constructor of a given object immediately lets you know which other objects it depends on. If your object has access to a reference to the Service Locator, you can get around this explicit dependency resolution and fetch a reference (and thus depend on) any other object from within the actual logic. This is what people refer to when they state that the Service Locator “hides” dependencies.

However, within the WordPress context, we need to accept that we’re already blocked from an ideal situation from the start. There is no technical possibility of having proper dependency injection throughout the entire codebase. This means that we have to put some compromise into the code either way. The Service Locator, although not a perfect solution, is a good fit within the such a legacy context, and at least allows you to have these “compromises” be located in one central place, instead of having your entire codebase be riddled with them.

Using Dependency Injection

If you are only working from within your own plugin and don’t need to provide access to your objects to other plugins, you’re in luck: you can use true dependency injection to get rid of the need to have global access to your dependencies.

// Interface, so that we can deal with multiple implementations and properly
// mock for testing.
interface DatabaseConnection {

   public function query( ...$args );
}

// The implementation we're currently using.
class MySQLDatabaseConnection implements DatabaseConnection {

   public function query( ...$args ) {
      // Execute query and return results.
   }
}

// We'll have to model the entire plugin to demonstrate this concept.
class Plugin {

   private $database;

   public function __construct( DatabaseConnection $database ) {
      $this->database = $database;
   }

   public function run() {
      $consumer = new Consumer( $this->database );
      return $consumer->do_query();
   }
}

// Consuming code.
// Also modeled as an entire class to demonstrate constructor injection.
class Consumer {

   private $database;

   public function __construct( DatabaseConnection $database ) {
      $this->database = $database;
   }

   public function do_query() {
      // Here's the actual consuming code.
      // At this point, it had an arbitrary database connection injected.
      return $this->database->query( $query );
   }
}

// Inject dependencies from the bootstrap code through the entire code tree.
$database = new MySQLDatabaseConnection();
$plugin   = new Plugin( $database );
$result   = $plugin->run();

This looks a bit more involved now, but keep in mind that we had to build a basic version of the entire plugin to demonstrate the dependency injection.

As we can’t have full dependency injection across the entire app, we can at least have it within the constraints of our own plugin.

This is an example of doing the actual wiring in a manual way, by explicitly instantiating all dependencies ourselves. In a more complex codebase, you’d want to look into using an auto-wiring Dependency Injector (a specialized container) that accepts upfront configuration information and that can then recursively instantiate your entire tree in one call.

Here’s an example of how this wiring would be done with such a Dependency Injector (given the same classes/interfaces as in the last example):

// Let the injector know what implementation to use for resolving the
// DatabaseConnection interface.
$injector->alias( DatabaseConnection::class, MySQLDatabaseConnection::class );

// Let the injector know it should always return the same shared instance
// for DatabaseConnection requests.
$injector->share( DatabaseConnection::class );

// Let the injector instantiate the Plugin class, which will cause it to
// recursively traverse all constructors and instantiate objects to
// resolve dependencies.
$plugin = $injector->make( Plugin::class );

Combinations

For more complex needs that are distributed across several custom and third-party plugins, you should look into combining the above approaches in ways that are adapted to your specific requirements.

As an example, I’ve been using the following approach with more complex client projects to get closer to the ideal approach I described further above:

  • Every plugin is instantiated through a centralized auto-wiring Dependency Injector.
  • Every plugin is a service provider that can register services with a centralized Service Locator.
  • Intra-plugin dependencies -> dependency injection.
  • Inter-plugin dependencies -> service location.
  • Third-party dependencies -> virtual services that wrap third-party functionality.

You can read more about this approach and see a recording of a case study talk on the Bright Nucleus Architecture page.

Conclusion

As you can see, there are several viable approaches to getting rid of your Singletons. While none of them are perfect in the WordPress context, they are all preferable to an actual Singleton, without exception.

Remember: the problem with Singletons is not that they are shared, but that they enforce their own instantiation.

If you think you know of a specific use case where the Singleton pattern is the only viable solution, please let me know, as I’d love to discuss!

All essays