Is There a Use-Case For Singletons With Database Access in PHP

Is there a use-case for singletons with database access in PHP?

Okay, I wondered over that one for a while when I first started my career. Implemented it different ways and came up with two reasons to choose not to use static classes, but they are pretty big ones.

One is that you will find that very often something that you are absolutely sure that you'll never have more than one instance of, you eventually have a second. You may end up with a second monitor, a second database, a second server--whatever.

When this happens, if you have used a static class you're in for a much worse refactor than if you had used a singleton. A singleton is an iffy pattern in itself, but it converts fairly easily to an intelligent factory pattern--can even be converted to use dependency injection without too much trouble. For instance, if your singleton is gotten through getInstance(), you can pretty easily change that to getInstance(databaseName) and allow for multiple databases--no other code changes.

The second issue is testing (And honestly, this is the same as the first issue). Sometimes you want to replace your database with a mock database. In effect this is a second instance of the database object. This is much harder to do with static classes than it is with a singleton, you only have to mock out the getInstance() method, not every single method in a static class (which in some languages can be very difficult).

It really comes down to habits--and when people say "Globals" are bad, they have very good reasons to say so, but it may not always be obvious until you've hit the problem yourself.

The best thing you can do is ask (like you did) then make a choice and observe the ramifications of your decision. Having the knowledge to interpret your code's evolution over time is much more important than doing it right in the first place.

Singleton or Dependency Injection pattern for database connection

A Singleton is a bad design in this case. Google would say it's a bad idea in all cases.

The right answer here is the connection pool.

You can avoid a max connections issue by configuring your pool to remain well below the limit and by making sure that your code rigorously closes all connections as soon as you're done with them. The cycle should be very short: check out of pool, execute SQL, close connection.

Why people use singletons in their PHP framework

Many reasons.

Static methods are basically global functions that can be called from any scope, which lends itself to hard to track bugs. You might as well not use a class at all.

Since you cannot have a __construct method, you may have to put an init static method somewhere. Now people in their code are unsure if the init method has been called previously. Do they call it again? Do they have to search the codebase for this call? What if init was somewhere, but then gets removed, or breaks? Many places in your code now rely on the place that calls the init method.

Static methods are notoriously hard to unit test with many unit testing frameworks.

There are many more reasons, but it's hard to list them all.

Singletons aren't really needed either if you are using DI.

A side note. DI allows for your classes not to rely on each other, but rather on interfaces. Since their relationships are not cemented, it is easier to change your application at a later time, and one class breaking will not break both classes.

There are some instances where single state classes are viable, for instance if none of your methods rely on other methods (basically none of the methods change the state of the class).

php singleton database connection, is this code bad practice?

Singletons are bad news.

  • They introduce global state into a program. Most programmers should be familiar with why global state is bad.
  • They introduce tight coupling between the singleton and any class that uses it. This means you can't reuse the classes in question without reusing the singleton too.
  • They make unit testing of classes that depend on the singleton problematic because you can't easily replace the singleton with a mock.
  • They encourage a coding style where classes attempt to resolve their own dependencies. This is bad because it can reduce clarity regarding what dependencies the class has.
  • PHP has a Share Nothing Architecture, meaning that PHP singletons aren't really singletons at all, there can be multiple instances alive at any one time (one per open request).
  • What happens if you suddenly discover at some later date that you actually need more than one of the resource that's being provided by the singleton? It's a more common scenario than you might think

You're better off looking at dependency-injection instead, as it resolves the above issues.

What is singleton in PHP?

A singleton is a particular kind of class that, as you correctly said, can be instantiated only once.

First point: it isn't a PHP related concept but an OOP concept.

What "instantiated only once means?" It simply means that if an object of that class was already instantiated, the system will return it instead of creating new one.
Why? Because, sometimes, you need a "common" instance (global one) or because instantiating a "copy" of an already existent object is useless.

Let's consider for first case a framework: on bootstrap operation you need to instantiate an object but you can (you have to) share it with other that request for a framework bootstrap.

For the second case let's consider a class that has only methods and no members (so basically no internal state). Maybe you could implement it as a static class, but if you want to follow design patterns, consider AbstractFactory) you should use objects. So, having some copy of the same object that has only methods isn't necessary and is also memory-wasting.

Those are two main reason to use singleton to me.

PHP - a DB abstraction layer use static class vs singleton object?

What is wrong with the following (simplified) example:

class Database
{
protected $_connection;

protected $_config;

public function __construct( array $config ) // or other means of passing config vars
{
$this->_config = $config;
}

public function query( $query )
{
// use lazy loading getter
return $this->_getConnection()->query( $query );
}

protected function _getConnection()
{
// lazy load connection
if( $this->_connection === null )
{
$dsn = /* create valid dsn string from $this->_config */;

try
{
$this->_connection = new PDO( $dsn, $this->_config[ 'username' ], $this->_config[ 'password' ] );
}
catch( PDOException $e )
{
/* handle failed connecting */
}
}

return $this->_connection;
}
}

$db1 = new Database( array(
'driver' => 'mysql',
'host' => 'localhost',
'dbname' => 'test',
'username' => 'test_root',
'password' => '**********'
) );

$db2 = new Database( array(
'driver' => 'pgsql',
'host' => '213.222.1.43',
'dbname' => 'otherdb',
'username' => 'otherdb_root',
'password' => '**********'
) );

$someModel = new SomeModel( $db1 );
$someOtherModel = new SomeOtherModel( $db2 );
$yetAnotherModel = new YetAnotherModel( $db2 );

This demonstrates how you can make use of lazy loading connections, and still have flexibility to use different database connections.

The database instances will only connect to their individual connection when an object that consumes one of the instances (in this case one of the models) decides to call a method of the instance.

Does a singleton instance make sense in this case?

A Singleton basically means you can only create 1 instance of a class, I personally don't see the point in hard-coding that into a class because generally speaking a class is something created so you can create multiple objects.

For your database example, for most websites only handling 1 database it should be fine. But what if in the future you want to connect to an external database using the same API? Ohh, you cannot because I implemented a singleton interface.

Now lets talk about your cookie example, each website has the ability to store multiple cookies. Why create a singleton out of that? Design that class so that $cookie2 = new Cookie('name') references to the other cookie. Yes, it can all be done with 1 class, a singleton where each time you need to parse a name to determine what cookie to put it in.

There are very few cases a singleton design pattern can be useful, at least in PHP. Most people use a container to store a variable that references to a single instance of a class (basically a singleton). However that container can be changed for another container, perhaps to something like a test environment referring to a different database and a different cookie all while using the same API.

PHP singleton database connection pattern

Using singletons in PHP is considered bad practice. From my experience the most problematic issue with them are unit tests. It is hard to ensure that two tests are independent when testing singletons.

I would delegate the responsibility for the constraint "only one instance should exists" to the code which creates the Db object.

Also for me it looks like there is a misunderstanding in how Singletons work in PHP in contrast to other languages: If you have 10.000 concurrent requests for example, then each request runs in a separate PHP process or thread, meaning they will all have their own instance of the "singleton", there is no sharing of this object for more than a single request (when running PHP in common web backend scenarios)

There is no "connection pooling" in PHP, but you can use mysqli persistent connections for mysql. It can be achieved by passing the p: in front of the hostname when creating mysqli. This might help here, but handle it with care (meaning read the documentation first)


However, just for theory, a singleton in PHP must be aware of the fact that someone could use clone. Meaning in your case it would be possible to do that:

$db = DB::getInstance();
$db2 = clone $db;

To avoid that you can implement the __clone() method like this:

public function __clone() {
throw new Exception("Can't clone a singleton");
}

Would singleton be a good design pattern for a microblogging site?

The Singleton's purpose is to limit object instances to one and to provide global access.

Both are things you don't want or need.

Limiting your instance to one instance is rather pointless in PHP where this restriction only applies to the instances in the current request. If two requests hit your microblogging site at the same time, there will still be one instance each per request. If you want to make sure there is only instance, simply do not instantiate a second instance.

Global access is nothing you want either, because it breaks encapsulation. If you need a certain instance inside your objects, pass it in via dependency injection. That's clean and maintainable. It has the added benefit of allowing you to easily exchange dependencies with other implementations, like for instance mock classes for your unit tests.

Even Erich Gamma, one of the Singleton pattern's inventors, questions this pattern nowadays:

"I'm in favor of dropping Singleton. Its use is almost always a design smell"

You are best off avoiding Singletons.



Related Topics



Leave a reply



Submit