Static methods vs singletons: choose neither

Posted by on March 3, 2010
 

StopwatchA post by Doru Moisa, Static call versus Singleton call in PHP, compares the performance of a singleton class with that of a static method. This is relevant, of course, because popular PHP frameworks such as symfony and Zend Framework make use of the singleton design pattern for their factory registry. What’s the verdict?

As you see, for a relatively small number of runs (<1k), the Static code is significantly faster than the Singleton, and it stabilizes at around 15% faster than the Singleton as the number of iterations grows, as I expected.

But look closer. The difference between the two methods equates to about 2.5 milliseconds per 100 calls. In the world of PHP frameworks, this is a miniscule price to pay for the added flexibility of a singleton (which, however, suffers from a number of drawbacks that I discuss below).

In the real world, not something to worry about

To put this in more concrete terms, I ran a large symfony application through Xdebug’s profiler. Symfony’s main singleton, sfContext, was retrieved a total of only 35 times. For a large project on a full-stack framework, the singleton’s cost is extremely low. The point? Focus on the important areas of optimization and don’t sweat the small stuff.

Much more important than performance is the fact that both static methods and singletons suffer from major drawbacks. When it comes to deciding between the two, you might forgo the benchmark comparison and choose the third-party candidate: dependency injection.

The dark side of static methods

Static methods can quickly lead to inflexibility and other problems. Specifically, static methods are very difficult to override and therefore nearly impossible to test. Sebastian Bergmann addresses this very issue in a recent blog post: Stubbing and Mocking Static Methods. The quote from Misko Hevery is particularly meaningful:

Yes, static methods are easy to call, but if the static method calls another static method there is no way to override the called method dependency.

The dark side of singletons

The slight performance loss when using singletons versus static methods is NOT their biggest problem. Singletons themselves always work through a static method. This means that, once again, they’re difficult to test. Sebastian tackles this topic as well in a comment to Derick Rethans’s blog post in which he references the potential answer to both static methods and singletons: dependency injection.

Why we use static methods and singletons

Two words: global scope. Static methods and singletons give us a way to reference variables (e.g. factories) that have not been passed to the current scope. Take this example from symfony, where I access the user factory from a class I’ve created:

class myClass
{
  public function __construct()
  {
  }

  public function doSomething()
  {
    $user = sfContext::getInstance(); // singleton accessor
    $user->doSomething();
  }
}

Dependency injection

The next generation of PHP frameworks will introduce a technique called dependency injection at their core. This removes the need for a “global scope” by passing any necessary dependencies through the constructor:

class myClass
{
  protected $user;

  public function __construct(sfUser $user)
  {
    $this->user = $user;
  }

  public function doSomething()
  {
    $this->user->doSomething();
  }
}

Instead of looking in the global scope for necessary resources, dependency injection encourages the practice of providing these resources directly. Without the need or a global scope, the need for singletons and static methods fades away.

Not performance, but smarter code

When deciding between using a static method or a singleton, performance should not be a consideration at all. Instead, take a moment to see if you can solve the problem in another way. Both static methods and singletons are frowned upon because they are difficult to test (amongst other things). If you are forced to use a singleton or a static method, choose what works best for you. Unless your application is doing some very serious lifting, performance should not be a concern.


About the author—Ryan Weaver is lead programmer at iostudio in Nashville TN and an avid supporter of the Symfony framework and open source in general. He's passionate about readable code, unit testing and collaboration (don't reinvent the wheel). If you've written open source code, Ryan probably loves you, but hates your documentation.