Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way to pass IoC container

I am getting my head around DI and IoC; using Pimple for now. Lets say I have my IoC defined early in the execution flow

$container = new Injection\Container();

$container['config'] = function ($c) {
    return new Config($c['loader']);
};

$container['request'] = function ($c) {
    return new Request($c['config']);
};

...

And a router class that call_user_func_array

//$class = 'Dog', $method = 'woof', $this->args = ['foo', 'bar']
call_user_func_array(array(new $class, $method), $this->args);

So new object is instantiated without being aware of the IoC but still I would like to reuse some of the services defined.

class Dog
{
    public function woof($var1, $var2)
    {
        //$request = IoC service here
    }
}

My question is:

  1. What would be the proper way to pass the IoC to the class (static seems to be evil...) or
  2. Is it even necessary to pass the container around and other methods/concepts exist?

Read some nice articles, however was not able to figure it out

  • Understanding IoC Containers and Dependency Injection
  • Why not pass your IoC container around?

Update

The evil way I did that was defining another service that saves the IoC in a static property

$container['services'] = function ($c) {
    return Services::create($c); //make the service
};

$container['services']; //call the service

and access it later in the

class Dog
{
    public function woof($var1, $var2)
    {
        $services = new Services();

        $request = $services['request']; //retrieving the request service
    }
}

Update 2

Decided to use the least harmful way

//passing the container here
call_user_func_array(array(new $class($container), $method), $this->args);

And store the parameter in __constructor

public $container;

public function __construct(Injection\Container $container)
{
    $this->container = $container;
}
like image 853
sitilge Avatar asked Sep 10 '15 20:09

sitilge


People also ask

What is the need for IoC container?

The IoC container that is also known as a DI Container is a framework for implementing automatic dependency injection very effectively. It manages the complete object creation and its lifetime, as well as it also injects the dependencies into the classes.

What is the difference between Spring container and IoC container?

An IoC container is a common characteristic of frameworks that implement IoC. In the Spring framework, the interface ApplicationContext represents the IoC container. The Spring container is responsible for instantiating, configuring and assembling objects known as beans, as well as managing their life cycles.

Which of the following is a IoC container?

ApplicationContext interfaces acts as the IoC container.

What is Spring IoC container?

Spring IoC Container is the core of Spring Framework. It creates the objects, configures and assembles their dependencies, manages their entire life cycle. The Container uses Dependency Injection(DI) to manage the components that make up the application.


1 Answers

There are 2 patterns that are commonly in use for IoC, and proponents for both.

  1. Dependency Injection
  2. Service Locator

However, it seems that more and more DI is winning out over the Service Locator pattern. Many DI containers are making it more difficult to use Service Locator and have warnings in the documentation not to go down that road.

In DI, you never pass the container to a class unless that class is part of the composition root. The composition root starts everything in motion by resolving the object graph at the entry point of the application, and from there on the application is entirely unaware of the DI container (has no reference to it). Note that this object graph may contain Abstract Factories that create runtime instances of classes (either by injecting a function to resolve from the DI container or simply by newing them up).

Service Locator is the other end of the spectrum. Typically the container is either made static or passed to a class as the only dependency. It might be easier to build classes this way, but you pay the price later when you actually have to configure the DI container.

With DI, the dependencies of a class are explicit so you need not look further than the constructor parameters. With Service Locator, configuring dependencies is much more complicated. This is the main reason (there are actually many reasons) why in recent years it is considered an anti-pattern.

So, to answer your question, if you want to follow the modern approach to IoC, don't pass the IoC container into the application. Instead, use a composition root at the entry point of your application to configure the container and build the object graph.

Dependency Injection Example

A complete example in PHP can be seen here. I found that page in a discussion on the Pimple project.

So, given your example:

class Dog
{
    public function woof($var1, $var2)
    {
        //$request = IoC service here
    }
}

You would need to add a constructor to accept your $request service so your class will receive an instance of it.

class Dog
{
    protected $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function woof($var1, $var2)
    {
        //Use $request here, disregard the IoC container
        $this->request->doSomething()
    }
}

And then you would have a section where you define controllers in your composition root. This is where the dependencies are injected.

$container = new Injection\Container();

$container['config'] = function ($c) {
    return new Config($c['loader']);
};

$container['request'] = function ($c) {
    return new Request($c['config']);
};

$container['dog'] = $container->factory(function ($c) {
    return new Dog($c['request']);
});

$container['user_controller'] = $container->share(function ($container) {
    return new UserController(
        $container['dog'] //,
        // $container['someOtherDependency']
    );
});

As you can see, using this approach your Dog class is completely unaware of the DI container.

like image 50
NightOwl888 Avatar answered Sep 19 '22 14:09

NightOwl888