tx9cgg
Last Updated: February 25, 2016
·
1.27K
· xander

Resetting Singletons in PHP - testing the untestable :)

Imagine the situation in which you are forced to use singletons. You're not exactly in charge of the architecture in your company, someone who is decided that he or she wants to have stuff written like that. Yet you are supposed to be writing testable code. Or maybe you have to write tests for some older code (we don't live in perfect world - such things happen from time to time ;] ) written in great times of ZF1.

But how to test singletons? How to determine the state of the singleton. The moment you do Classname::getInstance() you don't know if that object is just generated or maybe it was created earlier (in previous test maybe?) and it might already have state modified. How to do any assertions when you don't know what the state of the object is?

Singletons usually look like that:

<?php

class Classname {
    protected static $instance = null;

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

        return self::$instance;
    }

    protected function __construct() {}
}

In order to test the singleton we have to make sure it's state will be reset. To accomplish that we're going to use Reflections. Reflection API let us actually modify the protected properties. See below:

<?php

$singleton = Classname::getInstance(); // no idea what's inside
$reflection = new ReflectionClass($singleton);
$instance = $reflection->getProperty('instance');
$instance->setAccessible(true); // now we can modify that :)
$instance->setValue(null, null); // instance is gone
$instance->setAccessible(false); // clean up

// now recreate a fresh object
$singleton = Classname::getInstance();

And voilà! $singleton is now a fresh instance of Classname.

Got a better solution? I'm all yours :)