I’ve been thinking about singletons in PHP recently. There is an example in the PHP docs, which works well enough. Then I started looking for a way to have a singleton base class. My first few attempts failed, the key was to leverage late static binding, which was added in PHP 5.3.0.
[sourcecode lang=”php”]
 class Singleton {
 protected static $instance;
 private function __clone() { }
 private function __construct() { }
 private function __wakeup() { }
 final public static function singleton() {
 if ( !isset( static::$instance ) ) {
 static::$instance = new static();
 }
 return static::$instance;
 }
 }
 [/sourcecode]
This base class can be extended to create simple singleton classes, like so:
[sourcecode lang=”php”]
 class Example extends Singleton {
 protected static $count;
 public function add( $num = 1 ) {
 $this->count += $num;
 return $this->count;
 }
 public function get_count() {
 return $this->count;
 }
 public function subtract( $num = 1 ) {
 $this->count -= $num;
 return $this->count;
 }
 }
 [/sourcecode]
Here is what this looks like in action:
[sourcecode lang=”php”]
 echo "COUNT:n";
 $count = Example::singleton();
 echo $count->add() . "n"; // 1
 echo $count->add( 4 ) . "n"; // 5
 echo $count->subtract( 7 ) . "n"; // -2
 echo $count->add( 10 ) . "n"; // 8
 echo $count->get_count() . "n"; // 8
 echo "n";
echo "ANOTHER:n";
 $another = Example::singleton();
 echo $another->get_count() . "n"; // 8
 echo $another->add( 2 ) . "n"; // 10
 echo $another->subtract( 3 ) . "n";// 7
 echo $another->get_count() . "n"; // 7
 echo "n";
 [/sourcecode]
There are a few actions that the singleton class specifically fobids:
[sourcecode lang=”php”]
 // Each of these will throw an error
 $test = new Example();
 $test = clone $count;
 $test = unserialize( serialize( $count ) );
 [/sourcecode]
You could also do this via traits if you are using PHP 5.4.0 or newer. I wish PHP 5.0.0 had just gone with multiple inheritance in the first place.
One reply on “Extendable Singleton Base Class for PHP”
class Example1 extends Singleton {}
class Example2 extends Singleton {}
var_dump(Example1::singleton() === Example2::singleton()); // boolean true
print_r(get_class(Example2::singleton())); // IRRViewParserExample1