6

Possible Duplicate:
Who needs singletons?

i was wondering, what are the drawbacks using Singletons in php scripts. I use them alot and i sometimes can't understand criticism of developers. Some examples:

I have a Request class:

Sanitizing POST, GET, COOKIE inputdata and using it instead of the global arrays - strictly and globally. Like

$request = Request::getInstance();
$firstname = $request->post('firstname', $additionalFilters);

There is always only ONE request per request. Why is using singleton in this case a bad idea?

Same for $_SESSION:

I have a Session class (Singleton) which does represent the $_SESSION array because there is only one session and i use it globally.

Database

$mysql  = DB::getInstance('mysql', 'dbname'); //pseudo
$sqlite = DB::getInstance('sqlite', 'dbname'); //pseudo

For each type of database, i want only ONE object and never MORE. In my opinion there is otherwise a risk of chaos.

Unique rows

Also i often use classes to represent/use a unique row of a db table.

$article = Article::getInstance($id);
$navigation = Navigation::getInstance($id);

I see only benefits doing it this way. I never want a second object representing a unique row. Why is singleton such a bad idea here?

In fact, most (nearly all) my classes don't have a public constructor but always a static method like getInstance($id) or create() so the class itself handles the possible instances (which doesn't mean they are all singletons by definition)

So my question is: Are there any drawbacks i didn't realize yet. And which concrete scenario's the singleton-doubters thinking of when advise against Singletons.

Edit:

Now, you got a singleton that wraps around the $_POST, but what if you don't have $_POST, but want to use a file for input instead? In that case, it would be more convenient if you have an abstract input class, and instantiate a POSTInput to manage input through posted data.

Ok, valid advantages. I didn't realized that. Especially the point regarding the Request class.

Still i have doubts whether that approach. Assume i have a "Functionality" class which executes a concrete request (like a guestbook component). Within that class i want to get a sent parameter. So i get my singleton instance of Request

$req = Request::getInstance(); 
$message = $req->post('message');

This way, only my functionality object cares about a Request class.

When i use the non-singleton approach, i need somehow an additional class/function to manage that every request gets a valid request object. That way my Functionality class doesn't need to know about that managing class but in my opinion there still arises a dependence/problem: Everytime i create an instace of an Functionality object there is a chance that i forget to set a request object.

Surely i can define a non-optional parameter when creating a functionality. But that leads to a parameter overkill altogether at some time. Or not?

Community
  • 1
  • 1
player-one
  • 424
  • 4
  • 10
  • variables store only references of objects in PHP (unless you explicitly clone the object). Even if you do something like `$object2 = $object;` them both will refeer to the same instance. But i do like singleton too :p – Hugo Mota Aug 01 '11 at 17:13

2 Answers2

4

Singletons (and static classes, to which the same story largely applies) are not bad per se, but they introduce dependencies that you may not want.

Now, you got a singleton that wraps around the $_POST, but what if you don't have $_POST, but want to use a file for input instead? In that case, it would be more convenient if you have an abstract input class, and instantiate a POSTInput to manage input through posted data.

If you want to get input from a file, or even (for whatever reason) want to mimic (or replay) multiple requests based on input from a database table, you can still do this, without altering any code, except the part that instantiates the class.

Same applies to other classes too. You don't want your whole application to talk to this MySQL singleton.. What if you need to connect to two MySQL databases? What if you need to switch to WhatEverSQL?.. Make abstracts for these kinds of classes, and override them to implement specific technologies.

GolezTrol
  • 109,399
  • 12
  • 170
  • 196
  • I edited my question. It didn't fit in this comment box here, so therefore this message :) . Anyhow, thx for your great answer. – player-one Aug 01 '11 at 21:14
  • I think most of the systems will not talk to 2 databases (and switch over & back) at the same time. If it's really needed, like you said, subclassing a way to do so. – Raptor Dec 23 '13 at 12:24
3

I do not think singletons should have as bad press they do in a request-based architecture such as PHP or ASP.NET (or whatever you want). Essentially, in a regular program the life-time of that singleton can be as many months or years as the program is running:

int main()
{
    while(dont_exit)
    {
        // do stuff
        Singleton& mySingleton = Singleton::getInstance();
        // use it
    }

    return 0;
}

Apart from being little more than a global variable, it is very hard to replace that singleton with, perhaps, a singleton that might be useful in unit-testing. The amount of code that could depend on it, in potentially hundreds of source files tightly couples the use of that singleton to the entire program.

That said, in the case of request-based scenarios such as your PHP page, or an ASP.NET page, all your callable code is effectively wrapped in a function call anyway. Again, they are obfuscating a global variable (but within the context of the request) with safe-guards against being created more than once.

But still, I advocate against their use. Why? Because even in the context of your single request, everything is reliant and tightly coupled to that instance. What happens when you want to test a different scenario with a different request object? Assuming you coded using includes, you now have to go and modify every single instance of that call. If you had passed a reference to a pre-constructed Request class, you can now do cool stuff, such as provide mock unit-testing version of your class, by simply changing what gets passed down to the other functions. You've also de-coupled everything from using this universal Request object.

Moo-Juice
  • 36,340
  • 10
  • 69
  • 121
  • 1
    I know this is closed, but this is a great answer to this question! I get it now! Thank you so much, as a PHP'er I hadn't considered that in other languages that kept the singleton alive how hard it would be to change / replace it. Also, many thanks for the superb explanation on why you advocate against their use in single call languages, I dont think I will be using singletons ever again in PHP. – David Barker May 28 '12 at 15:27