I have a small framework and I coded it like this. I\'m not sure if it is called dependency injection or not. I don\'t know if it is like a design pattern or not. I also don\'t
You are almost there.
No, I don't see it as a valid dependency injection example. It resembles a bit a service locator (because you're injecting the entire container into your services and use it to "locate" dependent services).
You're making a small confusion between dependency injection and a dependency injection container.
First of, dependency injection means pushing dependencies into an object at runtime instead of creating/pulling them.
To exemplify this:
//hardcoded dependecies
class BadService
{
public function __construct()
{
$this->dep1 = new ConcreteObject1();
$this->dep2 = new ConcreteObject2();
}
}
So in the example above, the BadService
makes it imposible to wire other dependencies at runtime because they are already hard pulled into the constructor itself.
//service locator pattern
class AlmostGoodService
{
public function __construct(Container $container)
{
$this->dep1 = $container->getADep1();
$this->dep2 = $container->getADep2();
}
}
In the AlmostGoodService
example, we've removed the hard dependencies from the previous example but we are still depending on a specific implementation of our container (meaning that our service is not reusable without providing the implementation for that container). This is the example that matches what you're doing.
//dependecy injection
class GoodService
{
public function __construct($dep1, OptionalInterface $dep2)
{
$this->dep1 = $dep1;
$this->dep2 = $dep2;
}
}
The GoodService
service is not concerned with the creation of it's concrete dependencies and can easily be "wired" at runtime with any dependencies that implement the "protocol" of the $dep1
or the OptionalInterface for the $dep2
(therefore the name of Inversion of Control - the underlying concept behind Dependency Injection).
The component that does this wiring is called a dependency injection container.
Now, a dependency injection container, in it's simplest form, is nothing more than an object capable of wiring up your objects at runtime based on some form of configuration.
I said that you are almost there but there are some problems with your implementation:
$this
) as a dependency because then you fallback to a weaker inversion of control, namely a service locator. You should instead pass the concrete dependencies to your service constructorsThere are some cases when you'll find yourself wanting to pass the entire $container
as a dependency to a service (namely controllers or lazy service factories), but generally it will be better to stay away from this practice as it will make your services more reusable and easier to test. When you're feeling that your service has too many dependencies, then that it's a good sign that you're service does too much and it's a good time to split it.
So, based on my answers above, here is a revised (far from perfect) implementation:
/* This is the revised engine model */
class FrameWork_Engine_Model
{
function __construct($config)
{
$this->config = $cofig;
}
public function database()
{
require_once('Database.class.php');
return new Database($this->config['configParams']);
}
public function bbcode()
{
require_once('BBCode.class.php');
return new BBCode($this->database());
}
public function image()
{
require_once('Image.class.php');
$this->image = new Image($this->config['extensionName']);
}
....
public function register_controller($shared = true)
{
if ($shared && $this->register_controller) {
return $this->register_controller;
}
return $this->register_controller = new Register_Controller($this->database(), $thus->image(), $this->bbcode());
}
}
Now, to use your services:
$container = new FrameWork_Engine_Model();
$container->register_controller()->doSomeAction()
What could be improved? Your container should:
All of these are accompanied with clear documentation about Dependency Injection