user3526230
user3526230

Reputation: 1

PHP auto wire dependencies

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

Answers (1)

Lionel
Lionel

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

Related Questions