mardi 5 janvier 2016

Managing global dependencies

I am writing a fairly large application and have started to look into different design patterns to write 'better code'. I have started with PHPUnit and have discovered that my code will not be easily testable without dependency injection, as I will not be able to inject mock classes without it. I'm fine with the idea of dependency injection.

What I am having issues understanding is more to do with the management of dependencies in the project. Specifically, those I would have made global, such as a database connection. So now, instead of being a global variable, I must inject this as a dependency - that's fine.

However if I have a large number of function calls between instantiation of the database object, and where it is actually required, this is where it starts to get a bit confusing for me. It doesn't make sense to me that each function would then have a dependency upon the database object. Nor would it make sense to me to put it in a dependency container with all my global dependencies and have every function in my code have a dependency on the container.

Imagine a number of nested function calls, as follows.

<?php

    function foo()
    {
        bar();
    }

    function bar()
    {
        // Now we need to inject an instance of Database, but we don't have it!
        baz();
    }

    function baz(Database $database)
    {
        // work with the database here
    }

    $database = new Database();
    foo();

I can initialise my database, I may even put it in a container. The database class would only be created once, and would be global for the application. However with the code above, if baz does some database operation, now I would have to pass database as an instance to both foo and bar. If I put the database in a container, then I pass the container instead. However foo and, perhaps, bar need not care that baz is working with the database. And due to the nature of the Database class, it would be poor design to instantiate the database every time I need to use it.

I have thought about how I could combat this issue, one of my ideas was to use a static ::getInstance method, however the more I read on DI, the less I like this method, I just feel like it is wrong and that I'm going about it all the wrong way.

Another option I can see would be to have a container class that would have purely static get/set methods, and a static private array to contain the data. However all I achieve there is encapsulating the global scope.

How should I go about managing my global dependencies, and passing through the chain from instantiation to injection?

Aucun commentaire:

Enregistrer un commentaire