Singleton

Somehow I thought the singleton pattern would be pretty useful for my Request and Response classes, because they’re unique things and there should be only one object of them. They shouldn’t get initialized over and over again. PHP is request based, which means, once you got the output of your php script, the request is finished. Reloading the page will just cause a new request. That means if you write a Request or a Response class it doesn’t make much sense to initialize them more than once. At least, that’s my opinion.

Before I played around with the singleton pattern I was handing the request and response class to every class which would need them, which is not what I want. I can either initialize the Request in every class which needs to access Request data, or I hand the object through as method parameter – Using static and the singleton pattern this is not required anymore.

Let’s use the following code as starting point:

<?php
class Singleton{
	public function __construct()
	{
 
	}
}
 
class SingletonFoobar extends Singleton{	
}
 
$a = new Singleton;
$b = new Singleton;
?>

The Code results in no error. So everything is fine. Is it? No: It shouldn’t be possible that the class gets initialized more than once („new Singleton“ is there two times) and it shouldn’t be possible for child classes to override methods („extends Singleton“ I would really dislike that here). The second goal can be achieved by using the „final“ keyword in front of the class:

final class Singleton{

Now the code results in:

Fatal error: Class SingletonFoobar may not inherit from
final class (Singleton) in Singleton.Class.php on line 10

Good, let’s go on, remove the SingletonFoobar class. That was just there as an example. Using the singleton pattern we want that the class can only be initialized once. To achieve this we need to make sure nobody can call new Singleton anywhere. To do so make the constructor private:

<?php
final class Singleton{
	private function __construct()
	{
 
	}
}
 
$a = new Singleton;
$b = new Singleton;
?>

This results in:

Fatal error: Call to private Singleton::__construct()
from invalid context in Singleton.Class.php on line 9

So far, so good. But how to initialize the class now? There has to be a static method called getInstance, which initializes the object if not done already and returns the object, just to make sure we echo a message in case the object was already initialized – so you can see that the class really gets initialized only once:

<?php
final class Singleton{
	public static $instance;
	private $test;
	public static function getInstance()
	{
		if(!self::$instance)
		{
			self::$instance = new self();
			return self::$instance;
		} else
		{
			echo "initialized already";
		}
	}
 
	private function __construct()
	{
		$this->test = "foo";
	}
}
 
$a = Singleton::getInstance();
$b = Singleton::getInstance();
 
var_dump($a);
var_dump($b);
?>

That code results in:

initialized already
object(Singleton)#1 (1) {
  ["test":"Singleton":private] => string(3) "foo"
}
NULL

What did happen now? I called Singleton::getInstance(); which itself is checking if it is initialized already or not – If it is not, it will initialize itself and return itself (the object) if it is initialized already it will return (for debug purposes) the message „initialized already“. As you can see in the var_dump of $a the constructor still works – It is declared private, which means you cannot use new Singleton but the method getInstance can still access it fine for initialization. The NULL just shows that $b is empty because initializing it failed. Let’s go on:

<?php
final class Singleton{
	public static $instance;
	private $test;
	private $anothertest;
	public static function getInstance()
	{
		if(!self::$instance)
		{
			self::$instance = new self();
		}
		return self::$instance;
	}
 
	private function __construct()
	{
		$this->test = "foo";
		$this->anothertest = "bar";
	}
}
 
$a = Singleton::getInstance();
$b = Singleton::getInstance();
?>

This results in:

object(Singleton)#1 (2) {
  ["test":"Singleton":private]=> string(3) "foo"
  ["anothertest":"Singleton":private]=> string(3) "bar"
}
object(Singleton)#1 (2) {
  ["test":"Singleton":private]=> string(3) "foo"
  ["anothertest":"Singleton":private]=> string(3) "bar"
}

The class gets only initialized once – And all you do is using getInstance to get the initialized object. Another example which might show this better is this one:

<?php
final class Singleton{
	public static $instance;
	public $test;
	private $anothertest;
	public static function getInstance()
	{
		if(!self::$instance)
		{
			self::$instance = new self();
		}
		return self::$instance;
	}
 
	private function __construct()
	{
		$this->test = "foo";
		$this->anothertest = "bar";
	}
}
 
$a = Singleton::getInstance();
var_dump($a);
$a->test = "juhu";
var_dump($a);
$b = Singleton::getInstance();
var_dump($b);
?>

What would you expect from the last var_dump? The constructor sets $this->test to „foo“ hence if you would use „new Singleton“ the last var_dump would return „foo“ but it won’t do this here, because $b is accessing the already initialized object. That means, you always get the current data, even if you’ve changed the data somewhere. The result is:

object(Singleton)#1 (2) {
  ["test"]=> string(3) "foo"
  ["anothertest":"Singleton":private]=> string(3) "bar"
}
object(Singleton)#1 (2) {
  ["test"]=> string(4) "juhu"
  ["anothertest":"Singleton":private]=> string(3) "bar"
}
object(Singleton)#1 (2) {
  ["test"]=> string(4) "juhu"
  ["anothertest":"Singleton":private]=> string(3) "bar"
}

How about the getters?

<?php
final class Singleton{
	public static $instance;
	private $test;
	private $anothertest;
	public static function getInstance()
	{
		if(!self::$instance)
		{
			self::$instance = new self();
		}
		return self::$instance;
	}
 
	private function __construct()
	{
		$this->test = "foo";
		$this->anothertest = "bar";
	}
 
	public function getTest()
	{
		return $this->test;
	}
}
 
$a = Singleton::getInstance();
echo $a->getTest();
?>

Results in:

foo

Simple, isn’t it? Now in another class, you don’t need to hand it the object as variable in a method, and you don’t need to initialize it using new. Just use $var = Class::getInstance and use $var as you would have done before.

Just after writing this article I took a look at wikipedia; there they also disallow the use of clone by declaring __clone private and they use a default value of null for $instance, so they can check if (NULL === self::$instance) { within getInstance. My code would look like this with the changes applied:

<?php
final class Singleton{
	public static $instance = null;
	private $test;
	private $anothertest;
	public static function getInstance()
	{
		if(is_null(self::$instance))
		{
			self::$instance = new self();
		}
		return self::$instance;
	}
 
	private function __construct()
	{
		$this->test = "foo";
		$this->anothertest = "bar";
	}
 
	private function __clone()
	{
	}
 
	public function getTest()
	{
		return $this->test;
	}
}
 
$a = Singleton::getInstance();
 
echo $a->getTest();
?>

No Comments

Post a Comment