I’ve been reading about Dependency Injection but the examples I’ve found just look like bad code to me, so my main question is am I right in thinking it is bad code, or am I misunderstanding the purpose of it, and is my example any better?
class Photo {
protected $db;
public function __construct()
{
$this->db = DB::getInstance();
}
}
So this is bad code, and the suggestion of Dependency Injection, due to the multitude of setters that might be created if we explicitly set every variable, is:
class Container {
protected $db;
public static newPhoto()
{
$photo = new Photo;
$photo->setDB(static::$db);
$photo->setConfig();
$photo->setResponse();
return $photo;
}
}
$photo = Container::newPhoto();
But correct me if I’m wrong, we’ve just built a class whose sole responsibility it is to build another class, seems quite pointless, and we are using static methods which is apparently a very bad idea.
The one benefit that I do see, which surprisingly to me isn’t mentioned is that we can now test the Photo class independently by using the setters, whilst in the first example we couldn’t.
Something like this makes more sense to me:
class Photo {
protected $db;
protected $config;
protected $response;
public function __construct($dbConn=null,$config='123',$response=true)
{
if(is_null($dbConn))
$this->db = DB::getInstance();
else
$this->db = $dbConn;
...etc
}
}
$photo = new Photo($dbConn);
The class builds itself, there is no need for the static method to actually be called, the class can be tested with dummy data if values are used otherwise it falls back on defaults (which seems to be the only point of the Container class), and the dependencies are still somewhat obvious as opposed to the Container.
This is not implementing dependency injection. It actually is just an example of poorly implemented static factory method (anti)pattern. Especially the magical methods
$photo->setConfig()and$photo->setResponse()which apparently do some work, but receive no parameters.And then there is this code:
Instead of just assigning values, you decide to hide the dependencies of it, and, if they are not provided, to take them from global scope. And of course, your constructor ends up containing quite a log of computation. Thus making it untestable.
Oh .. and then there is the magical boolean value. Whenever where is such a parameter assigned to a class in constructor, it is a clear sign that you actually needed two different classes, which implement same interface.
So.. to answer your question:
No. Your example is not better. You just combined the worst parts from both your earlier code example in single class definition.