![]() |
A Generic Singleton Base Class
I'm from a C++ background and a Singleton hater. C++ just doesn't need them! However, I've found they're actually very useful for databases in PHP.
Anyways, I was trying to find a generic base class for Singletons in PHP. It's actually quite easy to do in C++ (which is probably why Singleton overload is a big problem). Most articles I find offer something like this: PHP Code:
The cloning problem can be fixed by making the __clone function final and private in every class you want to be a singleton. Making __construct private prevents instantiation even by this class, not what you'd want at all. Anyways, I can't really be bothered ensuring every class has a private clone function and constructor. That leads to errors. And even if they did, this class could still instantiate non-singletons as well. So I came up with this: PHP Code:
The Construct function is called the first time a Singleton is created. This can be overrided in sub-classes to do any initialisation the object may need. The constructor and the clone function are declared final private - only accessible by this class and unavailable for overriding. Unfortunately, even if this constructor is private / protected this can be overrided by sub-classes as public if they are not final, which allows them to be instantiated more than once. This is the reason for the Construct() function. If you create this test file: PHP Code:
Quote:
When we try to create NonSingleton via Singleton, we get our exception as desired (which is uncaught in this case). The only potential problems I can see in this are: 1) You can instantiate the Singleton class itself as demonstrated in the above code. This could be prevented by checking the input value, but I don't think it's worth it - surely only the worst coders would do this? 2) Construct() can be overrided to be public. This could be good and bad, I'm not sure how I feel about it... 3) Overhead? Anyways, what do you guys think? Any other potential problems? Is this even gonna work? :) M |
I did think of another issue in this class. What if you want to pass in parameters on construction of a Singleton class? I'd argue against doing this as a Singleton is supposed to control its own construction, however it is possible to do:
PHP Code:
So with this test script: PHP Code:
Quote:
|
A much simpler way to pass multiple arguments via an array if you have Reflection available to you;
PHP Code:
|
Unfortunately newInstanceArgs() calls the constructor, which cannot be overriden by any derived classes in this implementation. The default constructor could be rewritten, but we would then just be shifting the call to call_user_func_array() into the constructor.
|
I use a (probably bastardized) version of the registry pattern, which I understood to be an extension of the Singleton pattern, minus the addition of the getInstace() method in each class. So with the exception of a few variations in the pattern to incorporate factories, I make wide use of the constructor and wasn't thinking along the same line of what you're trying to present. I guess you can chock that up to the time of night. *!*
Wait Just A Minute... I still don't get it. What's wrong with calling the constructor in a singleton? You're calling a method called 'construct' which just seems hackish to make something similarily named anyways, isn't it? Why not use the constructor already available to the class - regardless, it's still being stored in a static location, and you can still run an initial check to make sure it's an instance of Singleton first. I may not understand, I'm not very educated in design patterns, despite trying to learn, but it just seems to me there's no reason why not to use the constructor. -m |
The point is preventing anything else from creating another Singleton. A Singleton is supposed to guarantee that only one instance of the singleton class exists. Ever.
There's nothing wrong with it per se, it's a limitation of this particular implementation. The base Singleton constructor is declared final, so it cannot be overriden. The upshot of which is that any class that extends Singleton cannot override the constructor. This is to prevent someone from creating a subclass that overrides the constructor and makes it public, thus breaking the Singleton pattern. In C++ this can't happen, if a base class has a private constructor then all derived classes can only instantiate themselves. __construct() is still called, it just can't be overridden to take parameters or do anything else. This is the reason for the Construct() function that can be overridden in sub-classes if the singleton in question requires some kind of initialisation. Although perhaps a semantically better name for the function would have been Init(). This of course leads to the problem of: what if I want to pass in parameters to a singleton constructer. My second post above was my best effort to solve that problem. With that change, you just pass in the extra parameters after the class name when you call GetInstance(). I'm beginning to regret that second post now. Singletons created on first access should control their own construction. The simplest way to do this is to keep all constructors parameter free. Of course you could decide to not declare the constructor final, but you then have to remember that every class derived from Singleton needs a private constructor to work properly. To show by example if we do this instead: PHP Code:
PHP Code:
Quote:
|
By the way, I've just looked up that registry pattern and I think I like it! :)
|
I personally use a mix of the Singleton and Registry pattern with some property overloading.
Example: PHP Code:
|
| All times are GMT. The time now is 03:58 PM. |
Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0