One of the great things about dependency injection is that a class's dependencies are explicitly defined in its interface (ie constructor). If a dependency injection container is used, however, many of these dependencies are consolidated into one dependency (the container). Therefore, many of a class's true dependencies are hidden behind the container. How is this avoided so that dependencies are still explitly defined while using a dependency injection container?
-
1No class which consistently uses constructor injection depends on a DI Container. You may use a container to wire up such classes, but then again you don't have to. How is that not explicit enough?Mark Seemann– Mark Seemann2012-03-18 08:15:02 +00:00Commented Mar 18, 2012 at 8:15
-
If class A is constructed using a DI container, and A has-a B, and B has-a C, then how does C access its needed dependencies? How do classes a few levels down the call stack access deendencies?orourkedd– orourkedd2012-03-18 16:10:31 +00:00Commented Mar 18, 2012 at 16:10
-
They use Constructor Injection as well. So if C depends on D, it gets it through its constructor.Mark Seemann– Mark Seemann2012-03-18 17:21:42 +00:00Commented Mar 18, 2012 at 17:21
-
So all of my classes should have constructors like: __construct(DatabaseAdapter $db, Cache $cache, Logger $logger, ...) ?orourkedd– orourkedd2012-03-19 05:36:44 +00:00Commented Mar 19, 2012 at 5:36
-
Yes and no: they most likely shouldn't depend on cache, logger and other cross-cutting concerns: stackoverflow.com/questions/1708992/… stackoverflow.com/questions/8426132/…Mark Seemann– Mark Seemann2012-03-19 07:12:57 +00:00Commented Mar 19, 2012 at 7:12
3 Answers
It seems you can use 'depends-on' attribute in your bean definition to add an explicit dependency in your code. I have found a similar question here
Comments
Yes and no, it really depends on how you dependency injection container works.
I don't see any problem with this kind of code:
class Class1 {
/**
* @Inject
* @var Class2
*/
private $class2;
}
Even though the dependency will be injected by the container, the fact that Class1 depends on Class2 is fairly explicit. (dependency injection container used here is PHP-DI)
Comments
I asked this question 3 years ago and have since come to understand and love DI in statically typed languages.
It looks like when I asked this question I didn't understand the difference between a 'Service Locator' and a 'Dependency Injection Container' (DIC).
A DIC operates "below" the app and is responsible for constructing objects and building the object graph, typically during bootstrapping but before the app if fully bootstrapped. Classes should not be aware of a DIC and should not depend on it. The DIC should construct all of the class's dependencies and inject them as if the class was being instantiated by hand.
A Service Locator is an object that is passed around a system and used to find dependencies. Using a service locator obscures dependencies (the original problem I noticed when I was learning this stuff) and creates a system-wide dependency (i.e. the service locator itself).
Generally, I would avoid the service locator pattern (some call it an "anti-pattern"). Using a good DIC like Ninject or Symfony 2's DIC will let your classes focus on the business logic therein - not on finding dependencies.
Read Martin Fowlers article on Dependency Injection: http://www.martinfowler.com/articles/injection.html