Wednesday, February 02, 2005

How to Create a Singleton in PHP

Using singletons in PHP can have great benefits for an application. A singleton allows a single reference to be maintained during execution of the application. So for example, you could create a singleton that would hold a reference to a database connection. That way, when making multiple database calls, with the chance for easily making multiple connections to the database, you don't have to worry. Only one connection to a database would be created when using a singleton. In addition, it helps when trying to access an Object from multiple places when the data within that object needs to be persistent.

I've read a number of different threads and articles on creating a singleton pattern in PHP. None of them seemed very satisfactory to me. In the classic sense a Singleton should store a static reference of it's own instance. Since PHP only supports static variables within functions, doing this is a little wierd. So, I set out to create a simple pattern for creating singletons in PHP

The goals were as follows:

  1. Make the singleton in such a way that it can be called statically, such as
    $instance = Singleton::getInstance();
  2. Make the singleton a class, not just a function
  3. Make the singleton retrievable from within other arbitrary classes
  4. The Class should store and retrieve an instance of itself


The following code accomplishes these goals:


//THIS IS FOR PHP4
class Singleton
{
function &getInstance() {
static $obj;
if (!isset($obj)) {
// Assign a reference to the static variable
$v = &new Singleton;
$obj = $v;
}
return $obj;
}
}



The singleton requires only a method to retrieve it's instance. No constructor is required. Since the 'normal' way to make a singleton is by using a private constructor, and then an accessor to retrieve an instance of itself, stored statically, we can't make a traditional singleton. The static variable would need to be a member variable.

Instead, we have to use the means of static variables in PHP. Static variables have many idiosyncracies. Of particular note, they can only exist within functions, and they cannot store references (in PHP4). Therefore, we have to play a little bit of a trick to make this work.

First, the static variable to hold the instance needs to reside in the getInstance function. Kind of wierd, but it's the right way to do it.

Second, since static variables cannot hold variables passed by reference, the instance of the singleton class cannot be set on the static variable. To get around this, create an intermediate variable to set the reference to, then set the value of that intermediate variable to the static var. By looking at it, it seems that the reference would be lost, but that's not the case. It sticks. Try it!

Finally, PHP5 seems to solve lots of the above problems and work arounds. The most significant change is that references can be held by static variables. That means that there's no intermediate variable trick that needs to happen. In addition, there are private, protected, and public declarations for functions and variables. So a more true Singleton can be achieved in that regard as well.

A PHP5 singleton would look something like this:



class Singleton
{
function &getInstance() {
static $obj;
if (!isset($obj)) {
$obj =&new Singleton;
}
return $obj;
}
}

How simple can it get?

1 comment:

cenovis said...

Thanks for this. I was wandering around the internet looking for reasons why the singleton pattern for PHP never returns a reference like it does in most other languages. This post cleared it all up.