I’ve been very busy these last fews weeks and have neglected making any posts. While there are a variety of subjects I’d love to post about, they’ll most likely have to wait until the next year. However, I thought I might be able to throw up a quick example of how to use PHP Singletons and extending public classes.
The Singleton Pattern “is a design pattern that is used to restrict instantiation of a class to one object.” (Wikipedia) In PHP, a singleton is created by making the constructor protected or private. “How do you create an object then?” Its done in two parts. First, you make a static class variable that is private, to hold the instance. Second, create a static function to return the instance. Here is an example:
[php]
name = ‘John’;
}
static public function GetInstance()
{
// Check to see if the instance is null
if(!self::$_instance)
{
self::$_instance = new MySingleton();
}
return self::$_instance;
}
public function GetName()
{
return $this->name;
}
}
// Use the Singleton Class
$class = MySingleton::GetInstance();
echo “Hello, my name is: “.$class->GetName();
// Or you can call the function this way:
echo “Hello, my name is: “.MySingleton::GetInstance()->GetName();
?>
[/php]
Singletons can be create if you need only one instance of a class. You must be careful, however, because you don’t want to “lock” yourself into an implementation where you really need more than one instance.
Now, what if I want to have a singleton of a current class? Let me give you an example. I have a project with a User class. Its used all over the website for display user’s information. Now, I wanted to create a class called CurrentUser, which is a singleton that holds the instance for the currently logged in user. Why would I want to do this? Once I get a user’s information, I only want to have to retrieve it once. I was running into problems where different parts of the website would request the current user’s information over, and over.
So at first I tried to sub-class the User class. Something like this:
[php]
[/php]
There is only one problem: when I tried to declare the constructor private, it threw an error:
Fatal error: Access level to CurrentUser::__construct() must be public (as in class User) in /path/to/file.php on line 73
The problem is you can’t protect or privatize a public function. If a parent has a less restrictive function, it’s child cannot make it more restrictive. But with a singleton, the pattern’s goal is to restrict the construction of an object to ensure only one instance. So how do we overcome this problem? HAS-A relationship, instead of a IS-A.
HAS-A relationship uses class members instead inheritance to accomplish it’s design. Whats the difference? Instead of CurrentUser “being” a sub class of User, it “has” a member variable containing an instance of a User object. We then don’t have to worry about overriding the constructor. Here is how you could do it:
[php]
user = new User();
}
static public function GetInstance()
{
if(!self::$_instance)
{
self::$_instance = new CurrentUser();
}
// Instead of returning the singleton instance, return it’s user instance
return self::$_instance->user;
}
}
$user = CurrentUser::GetInstance();
?>
[/php]
Nifty how that works. As developers, its easy to think “sub-classing” is the best method. It feels very “OOP” and it works in many ways. However, many times our design in the long run is much more complicated than sub-classing can handle. HAS-A relationships can offer more flexibility in the long run. Hopefully this can help out some people, and give others an idea on how to make Singletons work for you.
Good stuff! Well written up, I’ve used a “registry” class in the past so I could store all kinds of data in one class rather than have lots of classes that effectively do nothing, but I guess both methods have their plus points.
LikeLike
I dont think that “static private $_instance = null;” is good idea. Why is private for, if you could access from outside, like self::$_instance? It’s not private then. Why you are not using $_instance variable as static in your GetInstance function?
LikeLike
Thanks for the question Timmy.
The reason for “static private $_instance” is for several reasons.
First, I declare it static so that the variable is the same across any and all instances of this class. It is important because I use a static method to retrieve this value. Static methods do not have access to “$this”.
Second, the private is to ensure that the only manipulation done to the $_instance variable is by the CurrentUser class. By declaring it private, only functions withint the CurrentUser class have access to it. Outside I couldn’t do “CurrentUser::$_instance;” to retrieve the object. You only can access it through the GetInstance function. This helps safe-guard against developers on accidentally breaking functionality.
I hope this helps.
LikeLike