Is there a use-case for singletons with database access in PHP?

seriousdev picture seriousdev · Jan 4, 2011 · Viewed 41.1k times · Source

I access my MySQL database via PDO. I'm setting up access to the database, and my first attempt was to use the following:

The first thing I thought of is global:

$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');

function some_function() {
    global $db;
    $db->query('...');
}

This is considered a bad practice. After a little search, I ended up with the Singleton pattern, which

"applies to situations in which there needs to be a single instance of a class."

According to the example in the manual, we should do this:

class Database {
    private static $instance, $db;

    private function __construct(){}

    static function singleton() {
        if(!isset(self::$instance))
            self::$instance = new __CLASS__;

        return self:$instance;
    }

    function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')

        return self::$db;
    }
}

function some_function() {
    $db = Database::singleton();
    $db->get()->query('...');
}

some_function();

Why do I need that relatively large class when I can do this?

class Database {
    private static $db;

    private function __construct(){}

    static function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');

        return self::$db;
    }
}

function some_function() {
    Database::get()->query('...');
}

some_function();

This last one works perfectly and I don't need to worry about $db anymore.

How can I create a smaller singleton class, or is there a use-case for singletons that I'm missing in PHP?

Answer

Gordon picture Gordon · Jan 4, 2011

Singletons have very little - if not to say no - use in PHP.

In languages where objects live in shared memory, 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 is still a completely different instance. Thus, one of the two main purposes of a Singleton is not applicable here.

In addition, many of the objects that can conceptually exist only once in your application do not necessarily require a language mechanism to enforce this. If you need only one instance, then don't instantiate another. It's only when you may have no other instance, e.g. when kittens die when you create a second instance, that you might have a valid Use Case for a Singleton.

The other purpose would be to have a global access point to an instance within the same Request. While this might sound desirable, it really isnt, because it creates coupling to the global scope (like any globals and statics). This makes Unit-Testing harder and your application in general less maintainable. There is ways to mitigate this, but in general, if you need to have the same instance in many classes, use Dependency Injection.

See my slides for Singletons in PHP - Why they are bad and how you can eliminate them from your applications for additional information.

Even Erich Gamma, one of the Singleton pattern's inventors, doubts this pattern nowadays:

"I'm in favor of dropping Singleton. Its use is almost always a design smell"

Further reading

If, after the above, you still need help deciding:

Singleton Decision Diagram