How many singletons?
Moderator: General Moderators
-
alex.barylski
- DevNet Evangelist
- Posts: 6267
- Joined: Tue Dec 21, 2004 5:00 pm
- Location: Winnipeg
How many singletons?
Can you think of?
So far I'm thinking front controller and registry are excellent candidates for registry implementation. I just read that Pet shop thread quickly and seen a quick comment by arborint or Maugrim that suggested the use of a singleton, but I am not sure what they were talking about.
I suppose a general rule of thumb is any object created in the initial application entry point (index.php) would be a good candidate?
Front controller, registry, maybe authentication?
I know this is sorta situation specific (I have about 6-7 objects in my bootstrap file which I want to limit to single instances which are specific to my project) but I'd like to hear your experiences, what kinda of objects did you find you wanted to limit to single instance only?
So far I'm thinking front controller and registry are excellent candidates for registry implementation. I just read that Pet shop thread quickly and seen a quick comment by arborint or Maugrim that suggested the use of a singleton, but I am not sure what they were talking about.
I suppose a general rule of thumb is any object created in the initial application entry point (index.php) would be a good candidate?
Front controller, registry, maybe authentication?
I know this is sorta situation specific (I have about 6-7 objects in my bootstrap file which I want to limit to single instances which are specific to my project) but I'd like to hear your experiences, what kinda of objects did you find you wanted to limit to single instance only?
I usually make singleton my Log class. This is in simple applications of course.
Log class initiates db connection on demand only and keeps this on db connection in use...not creating it each and every time.
Another thing is View engine, smarty in my case. Personally, have never needed two instances of this.
Log class initiates db connection on demand only and keeps this on db connection in use...not creating it each and every time.
Another thing is View engine, smarty in my case. Personally, have never needed two instances of this.
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
The Singleton is appropriate for maintaining single instance objects - the key thing to remember is that every time you use it, you are quite literally coupling the class using it to the class name of the Singleton. So it's good practice to limit it to a small number of objects where the benefits outweigh future maintainance issues (imagine editing dozens of files to change the class name of the Singleton, then add more Singletons and you see the problem). The second thing is not to turn classes into Singletons if they might be subclassed/substituted in the future - that will really mess things up.
So in the case of the ZF the Front Controller and Registry make sense - the FC is only referenced in one place (limited coupling), and the Registry need only be referenced in a handful of places (again, limited coupling) like the bootstrap file. Some related classes might escape any major issues if their coupling is by design. In any case a Registry should help limit the number of Singletons - I mean it's there to make registered values available on a global basis. I would assume jmut's Log class is in a Registry and the Singleton is mre of a control feature (keeping Logs isolated to a single instance), and not sitting in who knows how many classes as "Log::getInstance()".
You can imagine two Log objects, one created in error; one logging to the database, the other to the error_log. If our analysis tool is only looking at the output of one (the other shouldn't have been allowed) it could miss important data from the second.
On the flipside, you probably want to avoid Singletons in database connection classes (depending on design), esp. for large apps. It's a pain in the ass having to go back and refactor that out of all the client classes if you suddenly need to support more than one connection at a time.
So in the case of the ZF the Front Controller and Registry make sense - the FC is only referenced in one place (limited coupling), and the Registry need only be referenced in a handful of places (again, limited coupling) like the bootstrap file. Some related classes might escape any major issues if their coupling is by design. In any case a Registry should help limit the number of Singletons - I mean it's there to make registered values available on a global basis. I would assume jmut's Log class is in a Registry and the Singleton is mre of a control feature (keeping Logs isolated to a single instance), and not sitting in who knows how many classes as "Log::getInstance()".
Depends - another injection strategy like Registry or by-parameter (think of the ZF's Zend_Controller_Front::setParam() which pushes objects directly into action controllers) can render it unnecessary. Of course you can register or pass Singleton instances like any other object - the Singleton behaviour can be just a safety feature of sorts so client code is prevented from creating duplicate instances which might not all be acting consistently.I suppose a general rule of thumb is any object created in the initial application entry point (index.php) would be a good candidate?
You can imagine two Log objects, one created in error; one logging to the database, the other to the error_log. If our analysis tool is only looking at the output of one (the other shouldn't have been allowed) it could miss important data from the second.
On the flipside, you probably want to avoid Singletons in database connection classes (depending on design), esp. for large apps. It's a pain in the ass having to go back and refactor that out of all the client classes if you suddenly need to support more than one connection at a time.
> I try not to use any at all. I currently only have one, which is my settings class (which could be static anyway.)
I'm thinking that's a good rule of thumb. Although I have used them before, I have to admit that I really don't like the hard coupling, and I really don't like the harder refactorings when needed. A typical example of when I used to use a singleton is indeed a config registry, but now I instantiate that and just pass it on via a method of whatever class that (might) need it.
Now, I'm not saying Singletons are evil, because - by tradition - that would obligate me to write a blog post about it
It's just that I don't like them, for a number of reasons:
(1) Strong coupling.
(2) Hard(er) to refactor.
(3) Doesn't "feel" right.
Oke, maybe I should take some time to clarify that last one. The reason I say that is that there's no way of telling what class uses the singleton, it becomes like a global, where you *can* completely lose track of.
I'm thinking that's a good rule of thumb. Although I have used them before, I have to admit that I really don't like the hard coupling, and I really don't like the harder refactorings when needed. A typical example of when I used to use a singleton is indeed a config registry, but now I instantiate that and just pass it on via a method of whatever class that (might) need it.
Now, I'm not saying Singletons are evil, because - by tradition - that would obligate me to write a blog post about it
(1) Strong coupling.
(2) Hard(er) to refactor.
(3) Doesn't "feel" right.
Oke, maybe I should take some time to clarify that last one. The reason I say that is that there's no way of telling what class uses the singleton, it becomes like a global, where you *can* completely lose track of.
My biggest issue with Singletons is the difficulty of testing. Breaking the chain of dependencies can be difficult with them because, like you say, it is a hard coupling.
I also think sometimes, although they suit the situation well, they are just not needed. Front Controller, for example, is a popular place to use a singleton. Why? The Front Controller, by it's definition, is the only point of entry - there is no where else the object will be used, there will only ever be one instantiation of it, so why enforce a singleton upon it?
Especially in an application composed of PHP, or other request based language, where we don't have to consider the factor of concurrency 9/10 as far as our objects are concerned. (Concurrency only really kicks in when we design datasources and so forth.)
I also think sometimes, although they suit the situation well, they are just not needed. Front Controller, for example, is a popular place to use a singleton. Why? The Front Controller, by it's definition, is the only point of entry - there is no where else the object will be used, there will only ever be one instantiation of it, so why enforce a singleton upon it?
Especially in an application composed of PHP, or other request based language, where we don't have to consider the factor of concurrency 9/10 as far as our objects are concerned. (Concurrency only really kicks in when we design datasources and so forth.)
Well it depends. If you are single developer yes. But idea of all this is to constraint stuff by code...not by developer assumption.Jenk wrote:The Front Controller, by it's definition, is the only point of entry - there is no where else the object will be used, there will only ever be one instantiation of it, so why enforce a singleton upon it?
What if someone sits and use it as two front controllers - ok this might make no sense, and this might be crappy developer but still he will have the possiblity, while with singleton he will not.
So the problem is where you draw to line between common deveoper sense(thinks that even undocumented are so well known that could not be a problem) and strictness (making all possible code tricks (singltone in this case) to alleviate the burden of always knowing what should be single and not)
I use Singletons all the live long day ... in Java. In PHP, I think the core meaning of the Singleton pattern is lost (or at least blurred) since there's no way to ensure that application client A and application client B get the same instance of a class. This is due to the fact that in PHP - none of your application objects exist outside the context of a specific request.Jenk wrote:I also think sometimes, although they suit the situation well, they are just not needed.
For example - client A requests a PHP page with a singleton front controller. The server happily creates an instance of the controller and uses it to dish out the response. When client B requests the same page - the server will recreate a new single instance of the front controller to deal with that request. In Java, you can ensure that client A and client B get the same instance of the front controller - or any other singleton you define. In PHP, we can only ensure that our singletons are unique within the context of the current request.
On the other hand - there are certainly instances in which you might want to use a singleton to ensure that a single instance of a class is used during the course of a single request - for example, if your controller calls a command factory, and you want to use the same factory instance several times while processing a request. In these cases, it seems that static methods work just as well.
On the issue of coupling - you have to have some, or else your apps won't do much
-
alex.barylski
- DevNet Evangelist
- Posts: 6267
- Joined: Tue Dec 21, 2004 5:00 pm
- Location: Winnipeg
I'm not sure I agree with ya'all (popular opinion it seems) in that singletons are/hould be limited.
Like Maug said: There are intended to limit any object which only ever needs a single instance, to a single (or limited) instance(s). That said, there are several objects I can think of in my application which suit the singleton pattern.
I'm just curious, but I fail to see any "tight" or "hard" coupling between a singleton implementation?
Can you demonstrate with example?
Cheers
Like Maug said: There are intended to limit any object which only ever needs a single instance, to a single (or limited) instance(s). That said, there are several objects I can think of in my application which suit the singleton pattern.
I'm just curious, but I fail to see any "tight" or "hard" coupling between a singleton implementation?
Can you demonstrate with example?
Cheers
Code: Select all
class A
{
public function doSomething()
{
$var = SomeOtherClass::getInstance();
}
}It's also a smell because it's a pseudo global (for the exact same reason)
My point exactlympeacock wrote:I use Singletons all the live long day ... in Java. In PHP, I think the core meaning of the Singleton pattern is lost (or at least blurred) since there's no way to ensure that application client A and application client B get the same instance of a class. This is due to the fact that in PHP - none of your application objects exist outside the context of a specific request.Jenk wrote:I also think sometimes, although they suit the situation well, they are just not needed.
For example - client A requests a PHP page with a singleton front controller. The server happily creates an instance of the controller and uses it to dish out the response. When client B requests the same page - the server will recreate a new single instance of the front controller to deal with that request. In Java, you can ensure that client A and client B get the same instance of the front controller - or any other singleton you define. In PHP, we can only ensure that our singletons are unique within the context of the current request.
Yes, minimal coupling is what I am aim for. I much, much prefer to pass parameter objects, or even the name of the class needed as a string instead of letting the object hardcouple with the sibling object. I never know when I might want to swap out for a different object, or reuse with a different objectmpeacock wrote:On the other hand - there are certainly instances in which you might want to use a singleton to ensure that a single instance of a class is used during the course of a single request - for example, if your controller calls a command factory, and you want to use the same factory instance several times while processing a request. In these cases, it seems that static methods work just as well.
On the issue of coupling - you have to have some, or else your apps won't do much. The real question is how you can minimize coupling while maintaining decent cohesion and delivering your code on time, on budget, etc.
-
alex.barylski
- DevNet Evangelist
- Posts: 6267
- Joined: Tue Dec 21, 2004 5:00 pm
- Location: Winnipeg
Ok, so class A is now bound to class SomeOtherClass, is that your point? I think, in this case, thats more a case of choice rather than intrinsically the fault of a singleton.Jenk wrote:That's now coupled tightly, and makes it difficult to test.Code: Select all
class A { public function doSomething() { $var = SomeOtherClass::getInstance(); } }
It's also a smell because it's a pseudo global (for the exact same reason)
How is that any different from from creating an object directly inside another function - other than that object being local in scope (the concrete dependency is still there)? To remove that binding you could just pass the object instance to the function as a parameter or use a registry, if you felt that was a design smell.
- Maugrim_The_Reaper
- DevNet Master
- Posts: 2704
- Joined: Tue Nov 02, 2004 5:43 am
- Location: Ireland
Knowledge of class names is coupling. What if I wanted to subclass SomeOtherClass? What if I needed to mock it in unit tests? Using a Singleton here has effectively blocked both options until I go back and get rid of those Singleton references. It's those downsides that motivate programmers in PHP to minimise their number. Also it needn't be a concious decision - some of us apply TDD which means we simply bypass the Singleton without a second thought.Ok, so class A is now bound to class SomeOtherClass, is that your point? I think, in this case, thats more a case of choice rather than intrinsically the fault of a singleton.
You just resolved it yourself thenHow is that any different from from creating an object directly inside another function - other than that object being local in scope (the concrete dependency is still there)? To remove that binding you could just pass the object instance to the function as a parameter or use a registry, if you felt that was a design smell.