Skip to content

Instantly share code, notes, and snippets.

@Ocramius
Created July 20, 2012 17:02
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save Ocramius/3151903 to your computer and use it in GitHub Desktop.
Save Ocramius/3151903 to your computer and use it in GitHub Desktop.
DIC container 101 in PHP
<?php
class B {
protected $c;
public function __construct(C $c) {
$this->c = $c;
}
}
class C {}
class MyContainer
{
protected $instances = array();
public function __construct()
{
$this->instances = array(
'B' => function (MyContainer $container) {
return new B($container->get('C'));
},
'C' => function(MyContainer $container) {
return new C();
},
);
}
public function get($name)
{
$cb = $this->instances[$name];
if ($cb instanceof \Closure) {
$this->instances[$name] = $cb($this);
}
return $this->instances[$name];
}
}
$container = new MyContainer();
var_dump($container->get('B'));
@AmyStephen
Copy link

That's essentially what mine does - except there is an adapter and handlers for each service. But, all services are requested of the container and returned by the container. The only entry point to the Container is the Front Controller. Here's a UML diagram of sorts https://github.com/Molajo/IoC/blob/master/.dev/IoC.png

The question is - when you have a Service that is dependent upon another Service (let's say the Model is dependent upon the Database service.) Then, the Model requests the Database service in order to inject the database into the Model during construction.

That's why I passed the closure with the call back to the single entry point into the Container - so that - in this case - the model can getService('Database') to inject it in when it constructs the class.

Otherwise, I can't see how you could do that - especially considering you want lazy loading and run time variables are often necessary.

(Thank you so much - your help is appreciated)

@AmyStephen
Copy link

https://gist.github.com/Ocramius/3151903#file-basicdiccontainer-php-L20

Actually - you're doing exactly the same thing.

@Ocramius
Copy link
Author

@AmyStephen I am not sure what you mean by "exactly the same thing" - looking at https://gist.github.com/AmyStephen/5607606#comment-832169, the code is too stripped down to really follow all the steps.

There some sentences that I believe to be wrong:

Then, the Model requests the Database service in order to inject the database into the Model during construction.

and

That's why I passed the closure with the call back to the single entry point into the Container - so that - in this case - the model can getService('Database') to inject it in when it constructs the class.

Maybe it's just a language problem, but if I understand it correctly, you are trying to achieve lazy-loading by passing closures around your models.

The problem is essentially that the model itself (service? Don't call it "Model" please, "Model" could literally be anything :( ) requests services as far as I understand, and that breaks the DIP by making your object "aware" that it has to pull something.

It also breaks the LSP, since you now cannot inject a mock now, but instead rely on some callback-based signature, trusting the fact that the callback will retrieve a valid object.

In my opinion, you should first focus on writing it correct and forgetting about the lazy-loading problem. The DIC will eventually be able to produce lazy wrappers of your services.

I wrote extensively on this subject in an article that you've probably already read:

http://ocramius.github.io/blog/zf2-and-symfony-service-proxies-with-doctrine-proxies/ (read it later eventually)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment