PHP - a Db Abstraction Layer Use Static Class VS Singleton Object

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.

Performance of Singleton Class Instance Method vs. Static Class Method in PHP?

Check this chart :)

alt text

grabbed from this article

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.

Which pattern should I use for my unique instance of the User class?

Patterns are supposed to be a helpful guide, like a library of previously successful software abstractions. Too often these days people view patterns as being some kind of religion where things are either "right" or "wrong" regardless of the context of the program.

Think about what you want to achieve and map in out in a way that makes sense to you. Fuggering about with minute distinctions between this pattern and that pattern misses the point, and it won't get your program written. Learn by doing!

HTH.

When to use static vs instantiated classes

This is quite an interesting question -- and answers might get interesting too ^^

The simplest way to consider things might be :

  • use an instanciated class where each object has data on its own (like a user has a name)
  • use a static class when it's just a tool that works on other stuff (like, for instance, a syntax converter for BB code to HTML ; it doesn't have a life on its own)

(Yeah, I admit, really really overly-simplified...)

One thing about static methods/classes is that they don't facilitate unit testing (at least in PHP, but probably in other languages too).

Another thing about static data is that only one instance of it exists in your program : if you set MyClass::$myData to some value somewhere, it'll have this value, and only it, every where -- Speaking about the user, you would be able to have only one user -- which is not that great, is it ?

For a blog system, what could I say ? There's not much I would write as static, actually, I think ; maybe the DB-access class, but probably not, in the end ^^

Using classes in PHP to store function

See this excellent post:

Singleton Pattern vs Static Classes

More Resources:

How Bad Are Singletons?
Static DB class vs DB singleton object

Best practice on PHP singleton classes

An example singleton classes in php:

Creating the Singleton design pattern in PHP5 : Ans 1 :

Creating the Singleton design pattern in PHP5 : Ans 2 :

Singleton is considered "bad practice".

Mainly because of this: How is testing the registry pattern or singleton hard in PHP?

  • why are singleton bad?

  • why singletons are evil?

  • A good approach: Dependency Injection

  • Presentation on reusability: Decouple your PHP code for reusability

  • Do you need a dependency injection container

  • Static methods vs singletons choose neither

  • The Clean Code Talks - "Global State and Singletons"

  • Inversion of Control Containers and the Dependency Injection pattern

Wanna read more? :

  • What are the disadvantages of using a PHP database class as a singleton?

  • Database abstraction class design using PHP PDO

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

  • Modifying a class to encapsulate instead of inherit

  • How to access an object from another class?

  • Testing Code That Uses Singletons

A Singleton decision diagram (source):

Singleton Decision Diagram

PHP: Should I be creating objects of this class, or is static acceptable?

Would it be acceptable or preferable to simply make all of these
functions static? I see no reason to instantiate objects when there
would only ever be one

There is no reason to instantiate objects if all you ever want to do is what this class is capable of doing. By using static methods you are coupling all of your client code with the class by hardcoding the class name throughout your code base. If at some later point you decide that you might want a different item manager service to fulfill your requests you will most certainly have a bad day.

Note that "a different item manager" can be simply code for "a mock manager used to unit test the rest of your code". So even in cases where alternatives will never be supported, using statics like that makes your code practically untestable.

Of course, you have already mentioned that there could very well be a different item manager in place: if the current one accepts a mysqli object then obviously there is no abstraction layer between your manager code and the mysqli interface. If you want to use a different object to connect to Mongo, how is the current item manager code going to support both configurations? Won't you need to write a new item manager class? How are you going to integrate it with the rest of the code if the class name is hardcoded everywhere?

Let's also view the situation from the opposite side: what does static gain you?

Obviously it makes the item manager a "singleton" object, which may sound like a good idea because "there is only one of it". This idea cannot be dismissed out of hand in PHP (as in other languages where multithreading is supported and there are hidden cross-thread dependencies), but it still doesn't hold much water. If you want your item manager to be a singleton, then simply don't create a second instance. If you want to force this for some reason, use a static variable to count instantiations and throw if you try more than one. Finally, make the class final so that this limitation cannot be removed. The result: a singleton that is not static.

This is all that static has going for it, and in light of the above it's awfully weak to stand as an argument.

and there is no need for it to maintain class
members. So, should I use static methods or not? Why?

I 'm not sure what this means -- you say the constructor already requires a database driver object, which has every right to be a class member. This is another obvious hint that static is not the way to go here.

Can someone help me understand the benefit of using classes in PHP
BESIDES modularity (as I can achieve that same effect with files of
functions)?

I 'm not going to present obvious arguments for OOP here, but raise a counter-point instead: you can achieve the same runtime effect, but you most certainly cannot achieve the same levels of maintainability and debugability for your application. Why use an inferior solution?

Coming from a Java background, I recognize the benefit of OOP in a
persistent environment, as objects maintain data and states throughout
the life of the application. However, with PHP, the life span of a
script is a fraction of a second and all state information is stored
within a database. Almost all functions just manipulate the database,
so what's the purpose? Isn't it pointless to instantiate objects when
I can merely call functions?

The life span of a process is a fraction of a second. The life span of the code base is measured in months, years and decades. That's how long people will be maintaining it, and that's why we use OOP in the first place.

Global variables can hold state just as well as class members, and people have been maintaining state long before "object-oriented" was a term. The benefit of OO is managing the complexity of the source-code-level model of the code, a venture I would most certainly not agree to describe as pointless.



Related Topics



Leave a reply



Submit