views:

6092

answers:

8

What is the benefit of using singleton instead of global for database connections in PHP? I feel using singleton instead of global makes the code unnecessarily complex.

Code with Global

$conn = new PDO(...);

function getSomething()
{
    global $conn;
    .
    .
    .
}

Code with Singleton

class DB_Instance
{
    private static $db;

    public static function getDBO()
    {
     if (!self::$db)
      self::$db = new PDO(...);

     return self::$db;
    }
}

function getSomething()
{
    $conn = DB_Instance::getDBO();
    .
    .
    .
}

If there's a better way of initializing database connection other than global or singleton, please mention it and describe the advantages it have over global or singleton.

A: 

It is quite simple. Never use global OR Singleton.

1800 INFORMATION
Never say never...
Outlaw Programmer
When it comes to Singleton pattern, always say never
1800 INFORMATION
I hate the Singleton as much as the next guy but it does have its uses. What about logging?
Outlaw Programmer
What if you want more than one log provider? Who says I can't log to a file, and the console?
1800 INFORMATION
What if you want to have named classes? Even without static data, they're still const globals.
Steve Jessop
They're also singletons, if you have meta-classes.
Steve Jessop
Singletons can have state; you can call setters to change the output for a Logger, for example. They provide a convenient way to access objects without passing pointers all over the place. Sometimes this convenience increases coupling, sometimes it makes things simpler. Depends on the context.
Outlaw Programmer
Aside named classes, the main use I've found for Singleton is to represent something of which there objectively is only one in relation to my program or any conceivable program using my class's API. "The Operating System", for example. It's still risky in the sense that you might want to Mock it.
Steve Jessop
So you would then combine one anti-pattern (Singleton) with another (God Object)
1800 INFORMATION
Yes. And so do the designers of every major OOP language, by permitting global class objects. If you're a monotheist and you want an object to represent God, then what you're looking for is a Singleton God Object. Anything else is incorrect.
Steve Jessop
I also note that you've offered no reasons as yet why any of these patterns are contra-indicated. We could have an argument where I ask you rhetorically whether you would ever use the anti-pattern "integer". Would that be educational?
Steve Jessop
If I was a montheist and I wanted to create a God object, I might specify to use a MonotheistAbstractFactory Pattern to create my God Object? This would leave open the possiblility for polytheistic users to also use my program by specifying a PolytheistAbstractfactory.
1800 INFORMATION
As to why it is contra-indicated, if you agree that a Singleton is the same as a global variable then we must surely agree with each other that globals are bad and should be avoided.
1800 INFORMATION
Also Singleton is essentially un-testable and hides global state.
1800 INFORMATION
Should be avoided. Not must be avoided. It's useful for app code to be able to assume that there is only one God, and for the *test* code to have to go around the houses in some language-dependent way in order to do its job. Yes, Singleton is a global variable. So are named classes. Do you use them?
Steve Jessop
Proposed compromise: a singular God (just like there's only one PID 0), but 99% of code must find a Priest (or instantiate their own Prayer if protestant) and interact through that. That's easily testable. Anyway God, the everlasting, is immutable: vastly reducing the dangers of globals.
Steve Jessop
I think we've broken the limits of the comment functionality, though: feel free to lambast me for hinting that even the 'friend' anti-pattern accurately describes a domain someone may wish to model, and we can leave the issue open to interminable contention...
Steve Jessop
I don't really believe in weaselly recomendations. Never say "should" when you can say "must".
1800 INFORMATION
I'm going to post to my LJ on this and related holy wars. Come on over if you (or anyone) fancies joining in - URL should be obvious, and LJ accepts OpenID or anonymous comments.
Steve Jessop
+1  A: 

If you're not going to use a persistent connection, and there are cases for not doing that, I find a singleton to be conceptually more palatable than a global in OO design.

In a true OO architecture, a singleton is more effective than creating a new instance the object each time.

Crad
A singleton *IS* a global!
Wahnfrieden
+9  A: 

I'm not sure I can answer your specific question, but wanted to suggest that global / singleton connection objects may not be the best idea if this if for a web-based system. DBMSs are generally designed to manage large numbers of unique connections in an efficient manner. If you are using a global connection object, then you are doing a couple of things:

  1. Forcing you pages to do all database connections sequentially and killing any attempts at asyncronous page loads.

  2. Potentially holding open locks on database elements longer than necessary, slowing down overall database performance.

  3. Maxing out the total number of simultaneous connections your database can support and blocking new users from accessing the resources.

I am sure there are other potential consequences as well. Remember, this method will attempt to sustain a database connection for every user accessing the site. If you only have one or two users, not a problem. If this is a public website and you want traffic then scalability will become an issue.

[EDIT]

In larger scaled situations, creating new connections everytime you hit the datase can be bad. However, the answer is not to create a global connection and reuse it for everything. The answer is connection pooling.

With connection pooling, a number of distinct connections are maintained. When a connection is required by the application the first available connection from the pool is retrieved and then returned to the pool once its job is done. If a connection is requested and none are available one of two things will happen: a) if the maximum number of allowed connection is not reached, a new connection is opened, or b) the application is forced to wait for a connection to become available.

Note: In .Net languages, connection pooling is handled by the ADO.Net objects by default (the connection string sets all the required information).

Thanks to Crad for commenting on this.

Dr8k
I guess using singleton gives me the advantage of initializing the connection as late as possible, while if I use global, I'd probably initialize nearly at the beginning of the script. Am I correct?
Imran
Correct, if you were to go down this road the singleton would provide that advantage.
Dr8k
Actually, that all depends upon scale. In large scale web deployments, massive amounts of DB connections are evil. This is why apps like pgBouncer exist for PostgreSQL and Java does resource pooling.
Crad
True, but I think proper connection pooling is different to just using global conenction objects. Connection pooling still uses multiple connections, it just limits the maximum number and resuses them over time to allieviate setup overhead.
Dr8k
Note that "global" in the case of PHP doesn't make the variable global across PHP pages. It just means that it can be accessed from within functions.
Ates Goral
Valid point Ates
Dr8k
+1  A: 

On the given example, I see no reason to use singletons. As a rule of thumb if my only concern is to allow a single instance of an object, if the language allows it, I prefer to use globals

Dprado
A: 

In general I would use a singleton for a database connection... You don't want to create a new connection everytime you need to interact to the database... This might hurt perfomance and bandwidth of your network... Why create a new one, when there's one available... Just my 2 cents...

RWendi

RWendi
With initializing the connection in global scope, I'm initializing the connection once per page, and using that global variable in functions that need to interact with database.
Imran
Using a singleton for a database connection is not the same as not re-creating the connection upon each interaction with the DBMS.A singleton is just that; one instance of a given class, and the only one allowed to exist globally. You might need to connect to different databases at once.
Rob
i was refering to a singleton class that manages connections to the database. I dont see the point of creating a new connection object everytime you want to interact to a dbms. Of course if you need to connect to different database at once, you may need to create another connection object.
RWendi
+3  A: 

If you really must have a global, keeping it out of the root namespace is often a smart move.

So I prefer your "code with singleton", but NOT because it's a singleton: it needn't be. The Singleton pattern states that there can only be once instance of a particular class, anywhere - it doesn't mean that one instance of your class is special, and it doesn't mean that you suspect most callers will only want to use one instance of your class. In fact, what you've written isn't really a Singleton, because the class containing it is DB_Instance, but the object is of a type unrelated to that in the class heirarchy: PDO. There are 0 instances of DB_Instance, and as many instances of PDO as other code chooses to create.

Even if it was a true Singleton, unless there's something about PHP's PDO in particular that I don't know about, then I don't see what's inherently unique about a database connection. A class representing a database connection shouldn't be Singleton.

So, I slightly prefer "code with singleton", but only because you keep "the database connection that I care about" in a namespace related to databases.

So far I've left aside the issue of whether it should be global at all - designing code to avoid globals can be quite difficult, and easily gets out of hand if you just end up passing an object around everywhere that represents "everything I care about". A well-placed global might save time and effort. If it does, then since none of us is in the business primarily to win awards for clean software design, it might be the right thing to do.

However, if a global ever starts to have externally-measurable state, such that code using it needs to know anything at all about what other code might do to it before, after, or at the same time, then it is most likely a false economy. You will put more effort into keeping your global working than you would have put into avoiding a global in the first place. That's one reason design purists might say not to do it at all, or to restrict the use of globals to immutable objects.

Steve Jessop
+2  A: 

Both patterns achieve the same net effect, providing one single access point for your database calls.

In terms of specific implementation, the singleton has a small advantage of not initiating a database connection until at least one of your other methods requests it. In practice in most applications I've written, this doesn't make much of a difference, but it's a potential advantage if you have some pages/execution paths which don't make any database calls at all, since those pages won't ever request a connection to the database.

One other minor difference is that the global implementation may trample over other variable names in the application unintentionally. It's unlikely that you'll ever accidentally declare another global $db reference, though it's possible that you could overwrite it accidentally ( say, you write if($db = null) when you meant to write if($db == null). The singleton object prevents that.

Adam N
+15  A: 

I know this is old, but Dr8k's answer was almost there.

When you are considering writing a piece of code, assume it's going to change. That doesn't mean that you're assuming the kinds of changes it will have hoisted upon it at some point in the future, but rather that some form of change will be made.

Make it a goal mitigate the pain of making changes in the future: a global is dangerous because it's hard to manage in a single spot. What if I want to make that database connection context aware in the future? What if I want it to close and reopen itself every 5th time it was used. What if I decide that in the interest of scaling my app I want to use a pool of 10 connections? Or a configurable number of connections?

A singleton factory gives you that flexibility. I set it up with very little extra complexity and gain more than just access to the same connection; I gain the ability to change how that connection is passed to me later on in a simple manner.

Note that I say singleton factory as opposed to simply singleton. There's precious little difference between a singleton and a global, true. And because of that, there's no reason to have a singleton connection: why would you spend the time setting that up when you could create a regular global instead?

What a factory gets you is a why to get connections, and a separate spot to decide what connections (or connection) you're going to get.

Example

class ConnectionFactory
{
    private static $factory;
    public static function getFactory()
    {
        if (!self::$factory)
            self::$factory = new ConnectionFactory(...);
        return self::$factory;
    }

    private $db;

    public function getConnection() {
        if (!$db)
            $db = new PDO(...);
        return $db;
    }
}

function getSomething()
{
    $conn = ConnectionFactory::getFactory()->getConnection();
    .
    .
    .
}

Then, in 6 months when your app is super famous and getting dugg and slashdotted and you decide you need more than a single connection, all you have to do is implement some pooling in the getConnection() method. Or if you decide that you want a wrapper that implements SQL logging, you can pass a PDO subclass. Or if you decide you want a new connection on every invocation, you can do do that. It's flexible, instead of rigid.

16 lines of code, including braces, which will save you hours and hours and hours of refactoring to something eerily similar down the line.

Note that I don't consider this "Feature Creep" because I'm not doing any feature implementation in the first go round. It's border line "Future Creep", but at some point, the idea that "coding for tomorrow today" is always a bad thing doesn't jive for me.

Jon Raphaelson
Not sure, but I think you meant: public function getConnection() { if (!$this->db) $this->db = new PDO(...); return $this->db; }
Dycey
Thanks! Would I lose any of the benefits of using this method by using `return self::$factory->getConnection();` instead of `return self::$factory;` ?
Nico Burns