Terry Harvey

Design Patterns: Singleton

Despite being widely considered an anti-pattern, the singleton is an extremely commonly-used design pattern. Naturally, it’d be in a developer’s best interest to understand what it is. Let’s have a look at it in this article.

According to Wikipedia…

For those of you who are fluent in jargon, here’s what Wikipedia has to say on the matter:

The singleton pattern is is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalised to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects.

Problem

If you didn’t understand that, no worries – I’ve got you covered! As most of us will know, the purpose of a design pattern is to solve a common problem. Take the following class:

<?php

class Database
{
    protected $pdo;
    protected $host;
    protected $dbName;
    protected $dbUsername;
    protected $dbPassword;

    public function __construct($host, $dbName, $dbUsername, $dbPassword)
    {
        $this->host = $host;
        $this->dbName = $dbName;
        $this->dbUsername = $dbUsername;
        $this->dbPassword = $dbPassword;
    }

    public function establishConnection()
    {
        $this->pdo = new PDO($this->host . ':' . $this->dbName, $this->dbUsername, $this->dbPassword);
    }
}

In this real-world scenario, there is no reason why we would ever want more than a single instance of this class. In fact, having any more would likely do more harm than good by opening up unneeded TCP connections and, ultimately, wasting server resources. So the problem, in this case, is ensuring that there is only ever one, single instance of this class.

Solution

So there are, naturally, other solutions that don’t require the use of the singleton pattern. The obvious one would just be to simply instantiate the class and store the object in a variable.

$db = new Database('localhost', 'foo', 'root', 'password');
$db->establishConnection();

That’d work perfectly fine, but what if we want to use that Database object inside a function? We couldn’t use it as a regular variable as it wasn’t declared in the same scope. We could use the global keyword to allow access to the variable from within the scope of the function, but we all know global is bad. This is when a lot of people would make use of the singleton pattern.

Example

Below is an example of how you would implement the singleton pattern on our earlier Database class example.

class Database
{
    protected static $instance;

    protected $pdo;
    protected $host;
    protected $dbName;
    protected $dbUsername;
    protected $dbPassword;

    public function __construct($host, $dbName, $dbUsername, $dbPassword)
    {
        $this->host = $host;
        $this->dbName = $dbName;
        $this->dbUsername = $dbUsername;
        $this->dbPassword = $dbPassword;
    }

    public function establishConnection()
    {
        $this->pdo = new PDO($this->host . ':' . $this->dbName, $this->dbUsername, $this->dbPassword);
    }

    public static function getInstance()
    {
        if (static::$instance)
            return static::$instance;
        
        static::$instance = new self('localhost', 'foo', 'root', 'password');
        static::$instance->establishConnection();

        return static::$instance;
    }
}

So how does this work exactly?

  • Firstly, I’ve created a static $instance property. This will hold the single instance of the class, or in other words, the Database object.
  • I’ve also created a getInstance() method. This is the function we will call whenever we want to retrieve the instance of the class. It will return the instance if it’s already been created. Otherwise, it will create one, store it in the object, then return it.

Hopefully that made sense! We can then use the method like this – and this will work in any scope, so you don’t have to worry about whether it will work inside functions and the like.

$db = Database::getInstance();

Cloning Objects

Although it’s fairly uncommon, it is possible to clone objects in PHP using the clone keyword. If we want to ensure that there will only ever be one instance of our class, we need to make sure to disable this cloning “feature”. We can do this by declaring the __clone() magic method within the class and throwing an exception within.

public function __clone()
{
    throw new Exception('You can\'t clone a singleton!');
}

If magic methods are unfamiliar to you, check this PHP.net entry.

So What’s an Anti-Pattern?

An anti-pattern is a pattern that is considered bad practice by a lot of developers – and the singleton is one. Here’s why:

What’s the Alternative?

A good alternative would be to either use good ol’ dependency injection (view my previous article on dependency injection here), or to use some kind of inversion of control (IoC) container. A good example of this would be the Laravel Service Container. I’ll write about that at some point!