Singletons in programming are a great thing. They let us ensure that there is only ever one single object from a class in existance.
While this isn’t strictly how object orientated programming is meant to work, it does come in handy from time to time. A prime example is a settings object. You don’t want to have multiple objects created from this class scattered around your application, and you want to make sure that any settings made to it are carried on across your entire application, not just where that one object instance is.
In PHP, the code to create a singleton class is pretty straight-forward:
class SingletonClass {
static private $_instance;
private function __construct () {
} // __construct ()
static public function getInstance () {
if (is_null (self::$_instance)) {
$class = get_class ();
self::$_instance = new $class ();
} // if ()
return self::$_instance;
} // getInstance ()
}
$singleton_object = SingletonClass::getInstance ();
You can see that we are blocking the constructor function so that it can only be created when you are inside that actual class definition. You then get the single instance of this class by calling the getInstance() method. All of this ensures that there is only one single instance of this class used anywhere in your site, and any values set in it are constant everywhere that they are used.
In PHP you can’t extend a singleton class to create another singleton class.. Well, strictly you can but… If you extend a singleton class to be a new singleton class, the old singleton class is overwritten and won’t work. As an example, this doesn’t work. 🙁
class SingletonClass {
static private $_instance;
private function __construct () {
} // __construct ()
static public function getInstance () {
if (is_null (self::$_instance)) {
$class = get_class ();
self::$_instance = new $class ();
} // if ()
return self::$_instance;
} // getInstance ()
}
class StaticClass1 extends SingletonClass {
public function render () {
echo "<p>This is the first singleton class.</p>";
} // render ()
}
class StaticClass2 extends SingletonClass {
public function render () {
echo "<p>This is the second singleton class.</p>";
} // render ()
}
echo "<p>Singleton testing.</p>";
$singleton_1 = StaticClass1::getInstance ();
$singleton_2 = StaticClass2::getInstance ();
$singleton_1->render ();
$singleton_2->render ();
That ends up ging you errors and just being plain wrong and bad.
This brings us to Traits!
Added to PHP in 5.4, traits let us set up classes that “inherit” values and methods without actually needing to extend another class. This little feature not only lets us share code, it also lets us “inherit” from several Trait classes as well as allowing us to use a Trait as a base for multiple singleton objects!
In the example below, I’ve created two singleton classes that use the same Trait to enforce their singleton pattern. This works correctly, and makes life a whole lot easier.
trait SingletonTrait {
static private $_instance;
private function __construct () {
} // __construct ()
static public function getInstance () {
if (is_null (self::$_instance)) {
$class = get_class ();
self::$_instance = new $class ();
} // if ()
return self::$_instance;
} // getInstance ()
}
class StaticClass1 {
use SingletonTrait;
public function render () {
echo "<p>This is the first singleton class.</p>";
} // render ()
}
class StaticClass2 {
use SingletonTrait;
public function render () {
echo "<p>This is the second singleton class.</p>";
} // render ()
}
echo "<p>Singleton testing.</p>";
$singleton_1 = StaticClass1::getInstance ();
$singleton_2 = StaticClass2::getInstance ();
$singleton_1->render ();
$singleton_2->render ();
Long live singletons!