This month I’d like to write about singleton pattern and tell you how it’s described in Head First: Design Patterns book. This chapter was one of the shortest in the book, so far. I read it a while ago and wanted to post about it earlier but as always… lack of free time didn’t let me do this
Despite the fact we learn about what a singleton is at the beginning, there is still a case study which helps us learn more. This time it’s a chocolate factory! We’re presented with a controller class of chocolate boiler in Choc-O-Holic Inc. The class looks like this:
class ChocolateBoiler { private $empty; private $boiled; public function __construct() { $this->empty = true; $this->boiled = false; } public function fill() { if( $this->isEmpty() ) { $this->empty = false; $this->boiled = false; // fill the boiler with a milk/chocolate mixture } } public function drain() { if( !$this->isEmpty() && $this->isBoiled() ) { // drain the boiled milk and chocolate $this->empty = true; } } public function boil() { if( !$this->isEmpty() && !$this->isBoiled() ) { // bring the content to a boil $this->boiled = true; } } public function isEmpty() { return $this->empty; } public function isBoiled() { return $this->boiled; } }
The authors of the code made everything to prevent of happening something bad. Just look at all of the if
statements. It’s impossible to fill not an empty boiler, drain an empty boiler or not boiled content and boil an empty boiler or already boiled one. But things might get wrong if there are more ChocolateBoiler
instances. That’s why we’re asked to change a little bit the class and use singleton pattern:
class ChocolateBoiler { private $empty; private $boiled; private static $instance = null; public static function getInstance() { if( is_null(self::$instance) ) { self::$instance = new self(); } return self::$instance; } private function __construct() { $this->empty = true; $this->boiled = false; } public function fill() { if( $this->isEmpty() ) { $this->empty = false; $this->boiled = false; // fill the boiler with a milk/chocolate mixture } } public function drain() { if( !$this->isEmpty() && $this->isBoiled() ) { // drain the boiled milk and chocolate $this->empty = true; } } public function boil() { if( !$this->isEmpty() !$this->isBoiled() ) { // bring the content to a boil $this->boiled = true; } } public function isEmpty() { return $this->empty; } public function isBoiled() { return $this->boiled; } }
Now, when anyone tries to create an instance of ChocolateBoiler
she’ll have to use ChocolateBoiler::getInstance()
method. Otherwise this line of code:
$chocolateBoiler = new ChocolateBoiler();
restults with:
PHP Fatal error: Call to private ChocolateBoiler::__construct() from invalid context
After that we read the singleton pattern’s definition:
The Singleton Pattern ensures a class has only once instance, and provides a global point of access to it.
And basically the PHP part must end here. Rest of the chapter in the book describes some other issues developers should be aware of when implementing Singleton pattern in Java. The Java application might work in few threads. That means that different code lines might be executed separately. Authors describes few different ways of how to deal with multi-threading in Java.
Last time I’ve checked there were no core multi-threading concepts in PHP. However, you could find lots of solution which described how to simulate it. One of them was even lectured at our polish php event. I left links I’ve found on the Internet about PHP and multi-threading. But recently I’ve read about pthreads which is still an experiment.
Other examples
I didn’t search for it long, therefore I didn’t find any examples of how to implement Singleton in PHP with pthreads used. The only one common thing in the all PHP examples I’ve read is some more PHP magic In the examples above I used
__construct()
magic function but __clone()
and/or __wakeup
magic method is commonly used as well:
class SingletonExample { 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); } }
Singleton examples
- Interesting example of using Singleton pattern with method chaining example
- An example with a lot PHP magic
- Yavor
Multi-threading
- pthreads.org
- PHPMultiProcessing Examples by sp3esu from meetPHP
- Multi-threading strategies in PHP by Saidov
- Multi-threading or concurrent programming in PHP with lightweight processes
Other design patterns
Here is the list of described by me design patterns: