Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency-injection in real life

I am building a really minimal MVC framework to increase my PHP knowledge and challenge myself. I've come to the point where Classes begin to be dependent on each other to work. Dependency injection seems to be the solution to this and are used by some of the big frameworks around.

I've found Bucket on Github and have messed around it for a while to understand the basics. What I can't get my head around however is when it's appropriate to create a Container?

Making one big container including every possible class that may be needed seems nothing but counter-productive to me and I can't imagine that it is good practice. It seems like the recipe for bad performance at least.

In the alternative, which is to make multiple containers, I still don't get how the ever-stinking Singletons are not needed anymore.

Let's say that I would have the following code:

$session_container = new bucket_Container();
$session_container->create('Database');
$session_container->create('Database_Sessions');

$log_container = new bucket_Container();
$log_container->create('Database');
$log_container->create('Database_Log');

So here we have two containers, or in this case buckets for two totally different usages which are mutual by their dependency on the Database class.

My logic tells me that the above code will create two independent instances of the Database-class, meaning that I still would have to make the Database-class a singleton to ensure that concurrent instances of my database connection isn't occurring?

Is this correct?

like image 667
Industrial Avatar asked Feb 19 '11 12:02

Industrial


People also ask

What is an example of dependency injection?

What is dependency injection? Classes often require references to other classes. For example, a Car class might need a reference to an Engine class. These required classes are called dependencies, and in this example the Car class is dependent on having an instance of the Engine class to run.

What is the use of dependency injection in C# with real time example?

Using dependency injection, we can pass an instance of class C to class B, and pass an instance of B to class A, instead of having these classes to construct the instances of B and C. In the example, below, class Runner has a dependency on the class Logger.

How is dependency injection useful?

The dependency injection technique enables you to improve this even further. It provides a way to separate the creation of an object from its usage. By doing that, you can replace a dependency without changing any code and it also reduces the boilerplate code in your business logic.

What is dependency injection in simple terms?

In object-oriented programming (OOP) software design, dependency injection (DI) is the process of supplying a resource that a given piece of code requires. The required resource, which is often a component of the application itself, is called a dependency.


2 Answers

I don't know much about the specific lib, but assuming it lets you use a factory, let the factory return the same instance.

Edit: Ok, this is simply on the Bucket GitHub index page.

class MyFactory {
  function new_PDO($container) {
    return new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
  }
}

$bucket = new bucket_Container(new MyFactory());
$db = $bucket->get('pdo');

So in your case you could simply do:

class MyFactory {
   private $pdo;
   function new_Database($container) {
     if($this->pdo){
         return $this->pdo;
     }
     return $this->pdo = new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
   }
}
$factory = new MyFactory();

$session_container = new bucket_Container($factory);
$session_container->create('Database_Sessions');

$log_container = new bucket_Container($factory);
$log_container->create('Database_Log');

Something like that. Doesn't seem like rocket science.

Edit2: I don't have enough rep points to comment on the question (bit silly), but in response to your "modularity" concern: think of the container as the "glue" of your application. Indeed, if you have a large application, you may want to "glue" inside an isolated part of your application only. That is a valid encapsulation concern. But even then you still need a container that handles injection at the highest level of abstraction. If you just create a separate container for every part of your application, you either end up with unneeded duplication of instances, or you have to apply another level of instance management, which doesn't improve the encapsulation in any way: you're still sharing instances between different parts of your application.

My advice would be to use a single container at the bootstrap level. If you want added encapsulation for specific parts of your application (modules, plugins, whatever), use "child containers". A child container inherits the instances from the parent container, but the parent container knows nothing of the child (as far as he's concerned, he's still a bachelor ;)). Could be that Bucket supports this by default, I know other DI containers do. If not, it's really easy to implement using a Decorator. Imagine something like this:

class MyContainerType extends bucket_Container {

    private $_parent;
    private $_subject;

    public function  __construct($factory = null, bucket_Container $parent = null){
        $this->_parent = $parent;
        $this->_subject = new bucket_Container($factory);
    }

    public function get($key){
        $value = $this->_subject->get($key);
        if($value){
            return $value;
        }
        return $this->_parent->get($key);
    }
    /**
     * Override and delegation of all other methods
     */
}
like image 69
John Avatar answered Oct 22 '22 02:10

John


Making one big container including every possible class that may be needed seems nothing but counter-productive to me and I can't imagine that it is good practice. It seems like the recipe for bad performance at least.

On the contrary. This is exactly what you would do with a di container. The container will only instantiate objects on demand, so there is virtually no overhead to managing all you singleton-ish classes through it.

The biggest problem with di is to distinguish between shared objects (Things you would usually think of as singletons) and transient objects (Objects that have plenty of instances through a normal application flow.). The former are easily managed through di. The latter don't really fit. Having those two "kinds" of objects clearly distinguished may seem like a bit of a hassle, but is really a highly beneficial side effect of using a di container.

like image 22
troelskn Avatar answered Oct 22 '22 02:10

troelskn