John Squibb
Using a Singleton to Manage Your Singletons. Wait, What?
I use the Singleton Design Pattern quite a bit, so much in fact, that I needed something to make using Singletons more seamless!
If you're not familiar with the Singleton Design Pattern, or how it pertains to PHP, then I suggest you check it out here.
If you are familiar with the pattern, and like me, have grown tired of adding getInstance() to all your classes and privatizing their constructors, then say hello to the Singleton class, known among his inner circle, as Mr. Singleton.
What's Wrong with the Standard Singleton Implementation?
Nothing whatsoever! But in order to convert your class to use the Singleton pattern, you have to do just that: convert all your classes. That's great if the only implementation you ever intend to use utilizes the getInstance() method. This may be exactly what you want for your database abstraction layer, or your helper classes that aren't static, or one of a gazillion other Singleton-worthy classes.
If you're just trying to cut some overhead by ensuring that your classes only get instantiated once per execution, then the Singleton contract might not be appropriate. Additionally, if you didn't have to refactor all your classes and bind them to the pattern, why would you?
Enter Mr. Singleton.
What Mr. Singleton Does for You
Basically, Mr. Singleton is just a final class that can't be constructed, that sits around waiting for you to request a class. When you do, he assumes the role of elephant, remembering every class you ask him for. If you ask him for it again, he gives you the original instance back, thereby preventing the overhead of additional instances.
Since Mr. Singleton creates the actual object, and remembers its state, all you have to do is ask him for the object, run the methods, and move along. You get all the benefits of the Singleton pattern without the disadvantages of refactoring your code. You can reduce overhead, and leave any preexisting or future code intact!
But enough of the cheesy code personification, let's have an example, shall we?
The Singleton Class
The code is pretty simple, just a few static methods and a member array to hold the instances.
<?php
final class Singleton
{
/**
* Maintains collection of instantiated classes
*/
private static $instances = array();
/**
* Overload constructor
*/
private function __construct(){}
/**
* Manages instantiation of classes
*
* @param $class
*
* @return none
*/
public static function instance($class)
{
//instantiate class as necessary
self::create($class);
//return instance
return self::$instances[$class];
}
/**
* Creates the instances
*
* @param $class
*
* @return none
*/
private static function create($class)
{
//check if an instance of requested class exists
if (!array_key_exists($class , self::$instances))
{
self::$instances[$class] = new $class;
}
}
}
Let's test Mr. Singleton with a sample class and some calls.
You can place the sample code in its own file and include Mr. Singleton, or you can just append it to the same file.
<?php
/**
* Test Taco Class
*/
class Taco
{
private $shell = 'soft flour';
public function __construct()
{
print "constructed\n";
}
public function shell()
{
return $this->shell . "\n";
}
public function change_shell()
{
$this->shell = 'hard corn';
}
}
// Ask Mr. Singleton for a taco.
$taco = Singleton::instance('Taco');
print $taco->shell();
// We'd like to have another taco.
$taco2 = Singleton::instance('Taco');
// Ah, it's the same taco!
print $taco2->shell();
// Change the taco a bit
$taco2->change_shell();
print $taco->shell();
// Can we we have another taco?
$taco3 = Singleton::instance('Taco');
// Dang, it's the same taco.
print $taco3->shell();
Summary
I utilize Mr. Singleton in a lot of my projects, and have grown quite fond of the ability to use him for quick one-off method calls without having to create a new instance of the class I am calling, even if I'm not concerned about redundant instances. Since Mr. Singleton's instance() method returns the instance of the requested object, as shown above in the samples, you can easily chain the first method call right to the back of your request!
Extend and Improve
As always, this could be extended. A lot of Singleton implementations tend to overload additional magic methods, especially __clone(). My goal here is less of a code-by-contract, and more of an ease-of-use approach. If preventing the clone of your objects is important to your project, then by all means, overload the __clone() method.
Suggested Reading
PHP 6 and MySQL 5
by Larry Ullman
I keep a copy of Visual Quickpro Guide, PHP 6 and MySQL 5 on my shelf to loan out to new PHP developers that have done little more than dabble in PHP for their personal website, and so on.
I literally wore an older edition of this book out by reading it from cover-to-cover, re-reading it, and carrying it around with me everywhere I went.
It was like my first guitar, I used the heck out of it! As the name implies, this book is designed to get you going. Larry Ullman does a great job of teaching the basics so that you can get a dynamyic website
talking to a MySQL database, complete with forms, sessions, cookies, security mechanisms, and on and on...If you don't know PHP, but are looking for a great way to dive in, buy this book.
Suggested Reading
PHP Design Patterns
by Aaron Saray
Seasoned programmers looking for a good book on PHP design patterns will thoroughly enjoy PHP Design Patterns.
Weighing in under 250 pages of readable content, it presents a truckload of philosophy and pattern samples in a well-condensed format, with short, consistent chapters.
The title starts off with a quick explanation of patterns, champions their usage, and by chapter 3, the user is thrust right into the Adapter Pattern.
For the next seventeen chapters, the user is given a synopsis, a problem/solution summary, a UML diagram, and code examples for each of the patterns in the discussed in the book.
Generally, the code provides a typical approach, and then a modified approach using the chapter's pattern.
Tags: Singleton, Design, Pattern, seamless, getInstance, classes, PHP
Short URL: http://sqb.in/A2tI