Snippet: Singletons with PHP

Today's snippet describes the singleton pattern. The singleton pattern is a method of creating a class that statically maintains an instance of itself and ensures that no other instances can be created. This is useful for classes that implement app-wide services such as logging, DB access and other shared resources.

The basic requirements for a singleton class are as follows...

  • The constructor is private
    This ensures that nothing outside the class can create instances.
  • A static method exists that returns the instance
    When first called the method creates a statically stored instance of the class. Subsequent calls return the existing instance.
  • Magic methods to prevent the instance from being cloned or serialized (PHP-specific)
    PHP provides functionality to clone and serialize objects. By adding simple implementations of the __clone and __wakeup magic methods we can prevent this from happening.

That's basically it. Here's a simple example...

class Singleton
{
  static private $_instance = null;

  public static function & Instance()
  {
    if (is_null(self::$_instance))
    {
      self::$_instance = new self();
    }
    return self::$_instance;
  }

  private function __construct()
  {
    // Do normal instance initialisation here
    // Nothing singleton-related should be present
  }

  public function __destruct()
  {
    // This is just here to remind you that the
    // destructor must be public even in the case
    // of a singleton.
  }

  public function __clone()
  {
    trigger_error('Cloning instances of this class is forbidden.', E_USER_ERROR);
  }

  public function __wakeup()
  {
    trigger_error('Unserializing instances of this class is forbidden.', E_USER_ERROR);
  }

  private $var = '';

  public function SetVar($val)
  {
    $this->var = $val;
  }

  public function GetVar()
  {
    return $this->var;
  }
}

This is an extremely simple example but it demonstrates all of the core concepts. You use this class as follows...

$obj1 = Singleton::Instance();
$obj1->SetVar('some value');

$obj2 = Singleton::Instance();
echo $obj2->GetVar(); // This will echo 'some value'

If you attempt to clone or unserialize an instance your script will fail with an error.

I use this pattern all over the place and definitely recommend using it where it makes sense in your applications. An alternative would be to implement the entire class statically and to be honest I'm not sure whether there are advantages to either implementation. If someone knows please share in the comments.

That's it for this snippet, stay tuned for more. As always comments, questions, suggestions and requests are welcomed.

blog comments powered by Disqus