Reputation: 1
I'm trying to build a dependency injection container which could auto-wire in dependencies using type hints. The problem arises when dependencies have their own dependencies. In other words I want my dependency container to be able to handle unlimited nested dependencies.
For example auto wiring this class would be easy:
class Bar
{
public function __construct(Foobar $foobar)
{
$this->foobar = $foobar;
}
}
class foo
{
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
Now if bar also has a dependency i have to somehow inject foobar to bar and only then bar to foo.
class foobar
{
}
class Bar
{
public function __construct(Foobar $foobar)
{
$this->foobar = $foobar;
}
}
class foo
{
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
Upvotes: 0
Views: 457
Reputation: 2029
You need two things to achieve this: Recursion and Reflection
Here is a working example:
function instantiate($class_name) {
$reflection = new ReflectionClass($class_name);
$constructor = $reflection->getConstructor();
// If there is no constructor in class, return object as is
if(!$constructor) return $reflection->newInstance();
$dependencies = [];
$params = $constructor->getParameters();
foreach ($params as $param) {
// Check for type hints in constructor
$paramType = $param->getClass();
if($paramType) {
// If there are type hints, call this very function
// again (recursion) in order to fetch dependency
$dependencies[] = instantiate($paramType->name);
}
}
// Return object (resp. dependency if in recursion loop)
// while also passing required constructor parameters
return $reflection->newInstanceArgs($dependencies);
}
$foo = instantiate('foo');
If you print_r($foo) you'll then see that the object 'foo' contains its dependencies.
foo Object
(
[bar] => Bar Object
(
[foobar] => foobar Object
(
)
)
)
Upvotes: 2