"If you inject a container into your class, you are not using dependency injection"

Just read this article from Paul Jones:
http://paul-m-jones.com/archives/4742?utm_source=rss&utm_medium=rss&utm_campaign=if-you-inject-a-container-into-your-class-you-are-using-service-locator-not-dependency-injection

What do you think? Its a service locator disguising as dependency injection even if you pass the container in class constructor? What if you do have a class that requires 5+ dependent objects? Passing them all separately in constructor can be a problem especially if your class also accept other parameters. Its not a good idea to have your class methods accepting more than 5 arguments, same applies for constructors. What are the possible alternatives to pass a large number of dependent objects to another object instead of using DI container?

Well this reply to that post sums it up for me

@jcarouth 1 day ago
@pmjones Technically it is dependency injection still…just using service location. The dependency is the container. chuckles

In regards to your question, if you have 5 dependancies in a constructor, I think that those five together might be able to be condensed into a seperate wrapper?


class MyWrapper {
   pulbic function __construct(MyDepen1 $Depen1, MyDepen2 $Depen2, MyDepen3 $Depen3, MyDepen4 $Depen4, MyDepen5 $Depen5) {
       //assign to vars
   }
}

class MyClass {
   public function __construct(MyWrapper $Wrapper /*other args*/ ) {
      //access public vars in MyWrapper
   }
}

But these depends entirely on how those 5 dependancies are being used and all this really does is clean up code (depending on how you look at it). Id prefer to write in 5+ dependancies that tie right to what I need.

The quote in the title is correct. If you’re injecting the container into anything* then it’s abusing the pattern. It breaks Law of Demeter and suffers the problems listed here: http://misko.hevery.com/code-reviewers-guide/flaw-digging-into-collaborators/

  • With the possible exception of a factory class

Ditto all the above. If you pass the container, then your class becomes tightly coupled to that exact container with that exact configured set of services, and your class becomes tremendously less portable and less adaptable to change.

Regarding your constructor parameter problem, look up the builder pattern. It eases that exact problem.

In Symfony if a class had a significant amount of dependencies you would declare/map setter methods and pass each dependency individual via a setter. You would likely do this by using the services YAML file to declare the various services and attributes associated with them. You could do the same thing manually but in Symfony 2 it is much more elegant using YAML service container definition files.

So the good practice is to never use a dependency injection container and instead always pass dependent objects either as parameters in constructor, or use builder/setters to pass each other them one by one?

Sounds interesting, but dont you think a wrapper is basically no different from a dependency injection container?

The problem with setter injection for dependencies that are used outside the setter method is that it breaks encapsulation, you have to call the set methods before you can use other methods on the object. In practical terms that means it’s possible to have an object in the system which has been successfully constructed but is still incomplete. Consider this:


class Foo {
	private $dep;
	
	public function setDependency(SomeDependency $dep) {
		$this->dep = $dep;
	}
	
	public function someMethod() {
		$baz = $this->dep->xx();		
	}
		
}


class Bar {
	private $foo;
	
	public function __construct(Foo $foo) {
		$this->foo = $foo;
		$this->foo->someMethod();
	}
	
}

$foo = new Foo();
$bar = new Bar($foo);

//This will error, although Foo looks like it's been constructed it's still incomplete.

The problem here is that Bar::__construct must be given a fully constructed Foo object. Bar should be able to assume the Foo object is complete and able to fulfil its responsibility. However, there’s ambiguity here. Bar cannot make the assumption that Foo is fully constructed because there’s no way to know whether the setDependency() method has been called or not.

This ambiguity is bad because it breaks encapsulation and causes headaches for other developers because object state is not guaranteed. It breaks fundamental OOP principles so don’t use setters for dependencies!

The only time you can avoid that is when the dependency is not required for the objects functionality:


class Foo {
	private $logger;
	
	public function setLogger(Logger $logger) {
		$this->logger = $logger;
	}
	
	public function someMethod() {
		if ($this->logger) $this->logger->log('someMethod called');		
	}
		
}

However, most of the time setter injection is used for dependencies it’s not used in this way. You’d need an if() check every time the dependency is used.

I see, but what if your object has a good number of dependencies? Passing all of them to your constructor may not be a good idea, you dont want any methods(including constructor method) to take too many arguments.

If an object has a lot of dependencies then that could be a sign that it’s doing too much, and perhaps you should think about refactoring.

Ditto.

So does this all mean that the only sane place to use DIC is at the script startup to generate needed objects and then forget about it as we go deeper down the application structure?

By and large, yes, that’s correct. As you go deeper down the application structure, all the classes and mini-libraries should just use plain old DI. They shouldn’t require the existence of a container.