Sharing database object without singleton

Realizing that singletons are not good for writing testable code I have done some reading and found out that a much better pattern is dependency injection. I’ve seen some code samples that looked logical but they didn’t involve the case of a database object, which basically I need to have only one instance of in my whole application.

So far I have come to this conclusion if an object of class A is dependent on an object of class B:

  1. Class A should require object B in the constructor.
  2. The code that uses object A uses a factory to create object A so that it is not involved in the complexities of instantiating
  3. The factory instantiates object B and passes it to the constructor of object A and returns object A.

The problem with that is that the factory is not a singleton so it creates a new instance of classes each time. So if B is our database class that A depends on, then the factory will create a new instance of the database object each time it is called - unless it uses a singleton.

Does that mean that DI and Factory cannot be used to solve the problem? From what I have read the proper use of DI prevents me from having to pass objects down all the layers in my application just because one method somewhere deep needs it - but I can’t see how this can work for objects that really need to have only one instance like database connection. Am I doomed to passing Db around from one object to another multiple times or can I achieve it in an elegant way without using statics?

First, before we get into factories, the way it would work is that we would create one database object that would be shared by each instance of A.

$b = new B();

$a1 = new A($b);

$a2 = new A($b);

Now when we introduce a factory, we need to implement this idea of shared instances.

class BFactory
{
    static protected $shared = array();
    
    public function getB()
    {
        if (isset(self::$shared['b'])) {
            return self::$shared['b'];
        }
     
        $b = new B();
        
        self::$shared['b'] = $b;
     
        return $b;
    }
}

This still looks singleton-ish, and in a way it is. The important part is that the singleton/shared instance logic is no longer baked into the B class. B can be instantiated any number of times, and it’s only our specific application that decides it wants just one instance.

That B can be instantiated any number of times may actually turn out to be important. For example, there are cases where an application’s data might be spread across a couple databases. Our newly architected B and BFactory let’s us accommodate that quite easily.

class BFactory
{
    static protected $shared = array();
    
    public function getDefaultB()
    {
        if (isset(self::$shared['default_b'])) {
            return self::$shared['default_b'];
        }
     
        $b = new B('default connection info');
        
        self::$shared['default_b'] = $b;
     
        return $b;
    }
    
    public function getAnotherB()
    {
        if (isset(self::$shared['another_b'])) {
            return self::$shared['another_b'];
        }
     
        $b = new B('other connection info');
        
        self::$shared['another_b'] = $b;
     
        return $b;
    }
}

Jeff, thanks for explaining it so well, the code examples are very clear and help a lot. This idea of singleton-ish factory came to my mind but I wasn’t sure this was the way to go. Yes, I already know the class itself shouldn’t decide to be a singleton and when the responsibility for keeping one instance is moved to the factory it makes much more sense.

Lastly, I have two more questions about factories:

  1. Does it matter whether factory is used statically or as instantiated object? I have come up across many examples of factories implemented with static methods. Because they are very simple constructs I don’t think it matters much when used normally but avoiding static methods could potentially help with testing, am I right?

  2. Is it better to have one central factory per application that serves all kinds of objects, or is it better to have a separate factory for each type of object?

Yup, I think you’re right about that. In fact, in hindsight, I wish I hadn’t used a static property in my BFactory code above. But I was copying other sample code, and it was too late to edit my post. :confused:

As your application grows bigger, I think it definitely becomes better to have one central factory per application. After all, separate factories would need to know about each other anyway. For example, an AFactory would need to know about BFactory. The idea of “one central factory that serves all kinds of objects” is actually called a dependency injection container, and it’s become a staple among the newer and larger frameworks.

I wasn’t actually asking about the static property but about calling the whole factory statically. So this:


$factory = new BFactory();
$b = $factory->getDefaultB();

versus:


$b = BFactory::getDefaultB();

Is one of the above preferred?

And why do you wish you hadn’t used the static property? How else would you guarantee a single instance of B? Without a static property you would have to make sure you have a single instance of the factory being available in all scopes where you are calling it, which gets us to create one more layer in a form of a singleton to keep our factory instance the same everywhere - a bit superfluos, isn’t it? Or is there another way?

Thanks, it makes sense!

BTW, I have found Pimple, a DI container for PHP 5.3. It looks simple and the use of closures seems quite clever, do you think it’s a good one to use?

I lean toward the former, but I’m striving to find a specific, practical reason to justify that preference. Right now the best I have is a somewhat general rationale for avoiding static data, which is that our objects behave more predictably when they’re all instance-based.

If a class is all instance-based, then when we create a new object, we know we’re getting a clean slate, and any methods we call on that new object will behave in a predicable way. But if a class uses any static data, then even when we create a brand new object, it might still carry some state from other, past objects, and as a result, it might behave differently.

I wish I had avoided the static property for the reason above, but it’s possible that avoiding static is only feasible when we’re working with one central factory, rather than lots of separate factories. If it is feasible, then I suppose all the factories would have to be instantiated at the core/entry point/kernel of your application. Even if we switched to the “one central factory” approach, we would still need to create it at the core/entry point/kernel.

I do think that’s a good one. I’m generally impressed with most everything that Fabien Potencier writes. :slight_smile:

I don’t know if I fully understood what you meant but I imagine that when we get rid of the static property then yes, the factory would need to be instantiated at the entry point. But what next? I’d have to use the same instance of the factory in every place, so how do I get to it from different scopes? This would need a singleton with a static property in it to get me this one instance of the factory everywhere. Isn’t it then better to have the singleton-ish behaviour built into the factory itself and not have to use a separate singleton for the factory?

Thanks. I have also found Dice - TomB’s DI container. I think I’ll have a hard time deciding :slight_smile:

You actually shouldn’t need to get to it from different scopes. The factories (or your one central factory) should be handling all the creation and injection of dependencies. So if A depends on B, which depends on C, which depends on D, then the way it should play it is: the core of your application knows it needs A, so it asks the factory for it. The factory knows that A needs B, so the factory creates B. The factory knows that B needs C, so the factory creates C. And the factory knows that C needs D, so the factory creates D. Regardless of how deep this chain may go, none of the classes within that chain need to know about the factories. They just get their dependencies, with no knowledge about where those dependencies come from.

If it would help, instead of talking about A, B, C, and D, you could post some real class names you’re working with and their real dependencies, and we can work with that.

If you have any specific questions about it, feel free to ask :slight_smile: