Tired of writing getInstance() methods and overloading the __construct() and __clone() methods for all of my Singletons, today I developed a Singleton that can be extended.  The result is as follows:

class Singleton
{
	protected static $_instance = array();
	
	private function __construct()
	{
	}
	private function __clone()
	{
	}
	
	public static function getInstance()
	{
		$class = get_called_class();
		if (null === self::$_instance[$class]) {
			self::$_instance[$class] = new $class();
		}
		return self::$_instance[$class];
	}
}

The $_instance variable is an array because, as a static variable, it wouldn’t allow for more than one class to extend it. For instance, suppose two classes, Widget and Gadget, extend Singleton. When Widget is first created with Widget::getInstance(), if it weren’t an array, $_instance would be set to a Widget object. Since this variable is static, calling Gadget::getInstance() would just return the previously instantiated Widget object. So the solution to this problem was to make $_instance an associative array with the keys being the name of the calling class.

I use the get_called_class function to retrieve the name of the class calling getInstance. So if you call Widget::getInstance(), the result of get_called_class would be “Widget”. If you used the __CLASS__ magic constant, you would get “Singleton” which is not what we want. The problem with this is that get_called_class() was only implemented in PHP v5.3, so this won’t work with prior versions of PHP (which is what I’m using). Luckily I found this post which creates a suitable get_called_class() function if it doesn’t exist. The code is duplicated below, thanks to Septuro:

if(!function_exists('get_called_class')) {
	class class_tools {
		static $i = 0;
		static $fl = null;

		static function get_called_class() {
			$bt = debug_backtrace();

			if (self::$fl == $bt[2]['file'].$bt[2]['line']) {
				self::$i++;
			} else {
				self::$i = 0;
				self::$fl = $bt[2]['file'].$bt[2]['line'];
			}

			$lines = file($bt[2]['file']);
			preg_match_all('/([a-zA-Z0-9\_]+)::'.$bt[2]['function'].'/', $lines[$bt[2]['line']-1], $matches);
			return $matches[1][self::$i];
		}
	}

	function get_called_class() {
		return class_tools::get_called_class();
	}
}

It should be noted that if the child class has a constructor, it should be declared protected so the Singleton class can instantiate it upon the first call to getInstance().