Things That Matter Most

Things That Matter Most

  • Home
  • Business
  • Faith
  • Technology
  • Politics
  • Creative Writing
  • Email
  • GitHub
  • RSS
  • Twitter

Powered by Genesis

Making Singletons Safe in PHP

January 7, 2013 by Eric 12 Comments

Last time, I argued in favor of the Singleton pattern in WordPress.  Singletons make sense in WordPress specifically for several reasons:

  • They live in the global scope without using the already abused/overused global keyword
  • As a distributed application maintained by several hundred developers, they prevent problems that likely arise from others misusing your code

But one of the goals of object-oriented software development is to make your code reusable.  The Singleton pattern as I explained it last time isn’t really applicable outside of WordPress.  Typically, Singletons are a really bad idea.  But rather than get hung up on the term and settle for the knee-jerk “it’s bad, don’t use it” conclusion, let’s take a deeper look.  There’s a reason Singletons exist; they solve a specific problem.  So rather than reject them out of hand, let’s make a minor change to make them safe for general PHP use.

There were two major arguments against Singletons throughout the comments, Twitter posts, Y Combinator thread, and private emails that followed my last post. First, that Singletons introduce hidden dependencies in your code.  Second, that Singletons are nearly impossible to unit test.  Both of these arguments are valid, but I have counters to each.

Hidden Dependencies

Any parameters a function accepts are visible dependencies. But if the function requires something else to operate – i.e. an open database connection – that is referenced through a global variable rather than a parameter, that dependency is considered hidden. There is no way for a third-party to know about that functional dependency without actually viewing the implementation of the function. Hidden dependencies make it extremely difficult to code against an API because the API isn’t the whole story.

As an application grows, it’s easier and easier to take shortcuts to get things done.  WordPress, for example, globalizes many of its internal variables.  The entire post loop is set up specifically to abuse the fact that the $post object is global:

if ( have_posts() ) : while ( have_posts() ) :
  the_post(); // Populates global $post object

  // Filter and echo $post->post_title from the global $post
  the_title();

  // Filter and echos $post->post_content from the global $post
  the_content();

endwhile; endif;

To get around this hidden dependency, you inject it.  Rather than referencing the global post object inside the function (a hidden dependency that you can’t easily override at runtime), you pass a post object when you call the function.  This post object can then be substituted with another at runtime and the code is none the wiser.

// So instead of this function
function do_something_to_post() {
  global $post;

  $post->post_content = apply_filters( 'modify_content', $post->post_content );

  return $post;
}

// You'd use this function and pass $post with the call.
function do_something_to_post( $post ) {
  $post->post_content = apply_filters( 'modify_content', $post->post_content );

  return $post;
}

Your business logic shouldn’t ever have to know where the post object comes from, just what it looks like.  Abstract that functionality away and you can provide any object you want – a post pulled from the database, one parsed from a document in the file system, or one hard-coded in a unit testing framework.

In Singletons

When developers use Singletons, they’re often tempted to reference Singleton::get_instance() directly (which is akin to invoking a global variable). Instead, code should accept a parameter and expect it to have a particular signature.  In strictly typed languages like C and C#, you’d do this by specifying an interface the object is required to implement.

Dynamically typed languages like PHP don’t require that 1, but it’s a good idea to get in the habit anyway.  It makes your intention clear to other developers and makes your code – and its dependencies – self-documenting. Instead of invoking our Singleton object inside the function, we pass in an object that implements the same interface as our Singleton:

function save_data( IDatabase $db_connection ) {
  // The IDatabase interface specifies a persist() method. We don't
  // care what the object that gets passed in is, so long as it
  // conforms to the interface we expect to use.
  $db_connection->persist();
}
$connection = DB::get_instance();

save_data( $connection );

The IDatabase flag inside the function definition is what’s called Type Hinting in PHP. It forces the passed parameter to be of the specified type – or for classes/interfaces to be a child or implementation of that type. It’s not strictly required for dependency injection, but placing the type in the function call makes your intentions in the code crystal clear to the next developer who reads it.

Unit Testing

Every unit test should start from a clean slate.  Ideally, unit test should run independent of the database and filesystem.  This is actually my biggest problem with WordPress – since so many of its DB calls are hard-coded in the application, the unit test suite requires a database in order to run.  Bad form.

The problem with Singletons as I explained them in my last article is a global state – once they’re instantiated, they stick around.  Anything you do to a Singleton in one test is persisted and visible in other tests.  This global state makes testing a mess, and my (lazy) solution was to introduce a ::reset() method that flushed the stored instance between tests.

There’s a better way.

First, define the interface your Singleton object will implement. This isn’t a strict requirement, but it’s easy for other developers to look at an interface and grok the API you’re exposing.

Second, define an abstract class that implements this interface. Don’t actually include any abstract functionality (unless you really want to). The point here is to have the business logic of your Singleton encapsulated in a way that can’t be instantiated directly.

Finally, define a Singleton class that extends the abstract business logic class. The Singleton wraps things up in a nice, can-only-be-instantiated-once wrapper.

interface IDemo {
  function write( $file, $message );

  // These methods will be used to demonstrate state
  function increment( $step );
  function get_counter();
}

abstract class Abstract_Demo implements IDemo {
  protected $counter = 0;

  public function write( $file, $message ) {
    $fp = fopen( $file, 'a' );

    fwrite( $fp, $message . "\r\n" );

    fclose( $fp );
  }

  public function increment( $step ) {
    $this->counter += $step;
  }

  public function get_counter() {
    return $this->counter;
  }
}

final class Singleton_Demo extends Abstract_Demo {
  private static $instance = null;

  private function __construct() {}

  public static function get_instance() {
    if ( null == self::$instance ) {
      self::$instance = new self;
    }
    return self::$instance;
  }
}

$logger = Singleton_Demo::get_instance();
$logger->write( 'file.txt', 'This writes out to a file.' );

The incredibly basic example above introduces an interface to document the signature of our class, an abstract class to implement the business logic, and a final class to instantiate that logic.  As an abstract class cannot be directly instantiated, there’s no danger of anyone doing so without going through our Singleton.  In our live application, the Singleton prevents any other developers from accidentally making more than one copy of our class.

When it comes time to test, though, the unit test project can extend the class the same way the Singleton does, but with a public constructor.  Now, within our unit test suite, we can create a new instance of our class for every single test.

class Concrete_Demo extends Abstract_Demo {
  public function __construct() {}
}

$logger = new Test_Demo();
$logger->write( 'file.txt', 'This also writes out.' );

Since our multiple-instance class implements the same interface as our Singleton, we can substitute it for our Singleton in whatever methods rely upon it.

Testing the business logic used by our Singleton is also fairly straight-forward using this concrete class. Below is an example set of 4 unit tests. The first two illustrate the conflict presented by testing Singletons – the state set up by the first test bleeds over into and corrupts the second. The later two illustrate using a concrete extension of our abstract class to allow multiple-instantiation within our test suite.

class Demo_Test extends PHPUnit_Framework_TestCase {
  public function testSingletonDemo() {
    $singleton = Singleton_Demo::get_instance();

    $this->assertEquals( 0, $singleton->get_counter() );

    $singleton->increment( 5 );

    $this->assertEquals( 5, $singleton->get_counter() );
  }

  public function testSingletonDemoState() {
    $singleton = Singleton_Demo::get_instance();

    // A new test should start with a new state. But since we
    // manipulated our singleton in the last test, it already
    // has an internal state. This test will FAIL if run after
    // the preceding test. This illustrates why most developers
    // hate Singletons.
    $this->assertEquals( 0, $singleton->get_counter() );
  }

  public function testConcreteDemo() {
    $obj = new Concrete_Demo;

    $this->assertEquals( 0, $obj->get_counter() );

    $obj->increment( 5 );

    $this->assertEquals( 5, $obj->get_counter() );
  }

  public function testConcreteDemoState() {
    $obj = new Concrete_Demo;

    // We're testing a new instance, so the internal counter
    // is once again set to 0.
    $this->assertEquals( 0, $obj->get_counter() );
  }
}

// This class is included ONLY in the test suite. Not the live
// application. That way it's never accidentally used.
class Concrete_Demo extends Abstract_Demo {
  public function __construct() {}
}

Conclusion

The point of using a Singleton is to:

  • Ensure only one instance of your class ever exists
  • Provide a global entry point or reference to that instance of the class

Yes, most people (including myself) disdain global variables.  But we use them all over the place.  Consider what a PHP web application would look like without $_GET or $_COOKIE.  These are global variables that are baked in to the language, yet they slip our minds whenever we start the “all global variables are evil and developers who use them are too naive to know better” arguments.

Consider also the static Request and Response classes in C#.  They serve a similar purpose – only one instance of each exists, and they provide global entry points/references for the application.  You can create and use your own versions, but only through the behind-the-scenes HttpRequestBase and HttpResponseBase classes, which are both abstract serve a similar purpose as my abstract class above.

People hate Singletons not because Singletons are inherently bad, but because so many developers have used them too often and in improper scenarios.  If you take care in developing your application, you can use Singletons safely without introducing hidden dependencies and while still maintaining a properly unit-testable application.

Notes:

  1. Omitting type references in PHP is often considered “duck typing.” Basically, “if it walks like a duck and talks like a duck, it’s a duck.” So if the object passed in implements the methods you plan to use, it might as well be of the type you expected … even if it’s something else. A function can accept an array, but I can just as easily pass it an object that implements ArrayAccess and the function doesn’t know the difference. ↩

Share this:

  • Email
  • Print
  • Facebook
  • Twitter

Filed Under: Technology Tagged With: Class, Dependency Injection, Duck Typing, Global Variable, Method, Object-oriented Programming, PHP, singleton, Singleton Pattern, Software Design Patterns, Unit Test, WordPress, Y Combinator

Comments

  1. mbijon says

    January 7, 2013 at 11:50 pm

    This resolves my testability concerns, I like it.

    And as an *added bonus*, it’s enough code that anyone lazy isn’t going to try implementing it excessively.

    Reply
  2. mbijon says

    January 7, 2013 at 11:52 pm

    Incidentally, reading it here is completely different than the formatting in the email generated through Jetpack.

    I wonder who you could convince to add filters to Jetpack so we could remove extraneous formatting characters that don’t make it through emails…

    Reply
  3. mikeschinkel says

    January 9, 2013 at 8:39 am

    Hey @Eric, thanks for giving me a chance to review this before you published it. And since you invited my same comments on the blog, here goes.

    You know I advocate the use of singletons[1] for WordPress plugins too so I’m with you there. However when I see your approach that adds the singleton logic in a subclass rather than just have a ::reset() method I feel the cure might well be worse than the disease. I’d rather reduce the coding complexity and frankly put the singleton logic in an abstract base class, which is how I’ve been doing it for a while now and is the subject of a future post I have planned.

    FWIW. 🙂

    [1] http://hardcorewp.com/2013/using-singleton-classes-for-wordpress-plugins/

    Reply
    • Eric says

      January 9, 2013 at 9:07 am

      Fair enough. I keep the Singleton logic itself at the top, though, because placing anything static in a class that can be inherited by multiple other classes can lead to a lot of issues. I know you have some other solutions for that particular issue, and at that point it boils down to personal preference.

      Reply
      • mikeschinkel says

        January 9, 2013 at 9:14 am

        Agreed. If you are going to use a static var in a base class it typically needs to be an array keyed by subclass name, a container for a list of shared objects, or some other property that is intentionally shared across subclasses.

        Reply
        • Eric says

          January 9, 2013 at 9:19 am

          Like I said, personal preference 🙂 I understand why that approach works, I’m just not sold on actually using it in any of my projects just yet. Using statics and class inheritance that way feels … hacky to me, even though it’s a perfectly reasonable approach. I do look forward to seeing what you do with it, but I’ll wait a while before adopting it myself.

          Reply
          • mikeschinkel says

            January 9, 2013 at 9:22 am

            Hey, I thought I was agreeing with you, not contradicting! 🙂

            Reply

Leave a Reply Cancel reply

About Me

Eric is a storyteller, web developer, and outdoorsman living in the Pacific Northwest. If he's not working with new tech in web development, you can probably find him out running, climbing, or hiking in the woods.

Get the newsletter

loading Cancel
Post was not sent - check your email addresses!
Email check failed, please try again
Sorry, your blog cannot share posts by email.