Programming - The Singleton Pattern

September 2016

The singleton pattern is one the best-known and easiest to implement design patterns, but it is also one of most misused patterns and will often lead to the introduction of a global state in the system (create dependencies that are difficult to maintain or adapt).

If your system requires only a single instance of a class and you'd like to make the selected instance accessible system-wide, you may do so by making the class into a singleton. This guide will teach you how to implement a singleton class in PHP, and also how to overcome the limitations posed by the singleton pattern.

How To Implement a Singleton in PHP

Implementation Through a Static Method

The easiest way to implement a singleton class in PHP is to change the visibility of the constructor class (to prevent instantiation outside of the class) and then create the instance within a static method. Here's a simple example:

<?php
class Singleton {
   private static $instance = null;

   private function __construct()
   {
   }

   private function __clone()
   {
   }

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

$singleton = Singleton::getInstance();

// Generates a fatal error in PHP 7
// "Call to private Singleton::__construct() from invalid context"
$singleton = new Singleton();


This type of implementation has a major drawback. The use of a static method will make the system vulnerable to external attacks (e.g. unauthorized access to the data of a database through a simple SQL query).

Implementation Through a Factory Pattern

Instead of using a static method, we are going to use factory pattern to return the desired instance of the class. A result of using the factory pattern is that the constructor class becomes public. It enables the creation multiple instances of the singleton class, which kills the purpose of using a singleton pattern (single instance required).

Fortunately, PHP 7 provides a simple way to stop the creation of multiple instances. You simply have to create an anonymous class within the factory pattern:

<?php
class Factory {
    private $instance = null;
    
    public function getInstance()
    {
        if ($this->instance === null) {
            $this->instance = new class() {
                private $var;
                public function get() {
                    return $this->var;
                }
                public function set($value) {
                    $this->var = $value;
                }
            };
        }
        return $this->instance;
    }
}

$factory = new Factory();
$o = $factory->getInstance();
$o->set(5);
$o2 = $factory->getInstance();

// Affiche "int(5)"
var_dump($o2->get());


N.B. Type hinting is disabled when using an anonymous class of the object(class@anonymous) type. If you would like to enable type hinting, you simply have to implement an interface in the code:

<?php
interface MyInterface {
    public function get(): int;
    public function set(int $value);
}

class Factory {
    private $instance = null;
    
    public function getInstance(): MyInterface
    {
        if ($this->instance === null) {
            $this->instance = new class() implements MyInterface {
                private $var;
                public function get(): int {
                    return $this->var;
                }
                public function set(int $value) {
                    $this->var = $value;
                }
            };
        }
        return $this->instance;
    }
}

function display(MyInterface $object)
{
    var_dump($object->get());
}

$factory = new Factory();
$o = $factory->getInstance();
$o->set(5);
$o2 = $factory->getInstance();

display($o2);


The introduction of an anonymous class will lead to another problem. It is now possible to instantiate several factories and therefore create several instances of the singleton class. Anonymous classes will differ from one instance to another, and furthermore, the use of the static method will make it difficult to identify new instances.

To prevent our class from being instantiated multiple times and keep our instance safe within the factory pattern, we'll need to edit our code to:

<?php

class Factory {
    private $instance = null;
    
    public function getInstance()
    {
        if ($this->instance === null) {
            $this->instance = new class() {
                private static $instantiated = false;
                
                public function __construct()
                {
                    if (self::$instantiated) {
                        throw new RuntimeException('Could not instantiate class');
                    }
                    self::$instantiated = true;
                }
                
                private $var;
                
                public function get(): int {
                    return $this->var;
                }
                
                public function set(int $value) {
                    $this->var = $value;
                }
            };
        }
        return $this->instance;
    }
}

$factory = new Factory();
$o = $factory->getInstance();
$o->set(5);

$factory2 = new Factory();

$o2 = $factory->getInstance();
var_dump($o2->get());


This will put a stop to the creation of multiple instances of our singleton class, which in turn will make the anonymous class obsolete. We can now edit our code to:

<?php
class Singleton {
    private static $instantiated = false;
    private $var;
    
    public function __construct()
    {
        if (self::$instantiated === true) {
            throw new RuntimeException('Could not instantiate class');
        }
        self::$instantiated = true;
    }

    private function __clone()
    {
    }
    
    public function get(): int {
        return $this->var;
    }
    
    public function set(int $value) {
        $this->var = $value;
    }
}

class Factory {
    private $instance = null;
    
    public function getInstance()
    {
        if ($this->instance === null) {
            $this->instance = new Singleton();
        }
        return $this->instance;
    }
}

$factory = new Factory();
$o = $factory->getInstance();
$o->set(5);

$factory2 = new Factory();
// Generates the message: "Could not instantiate class"
$o2 = $factory2->getInstance();


The method described above has a major limitation. Once the class has been instantiated (an object has been created), you won't be able to test it. But fortunately, it can be solved through the implementation of a resetInstance() static method, which will allow you to create new instances at will.

Related :

This document entitled « Programming - The Singleton Pattern » from CCM (ccm.net) is made available under the Creative Commons license. You can copy, modify copies of this page, under the conditions stipulated by the license, as this note appears clearly.