Search code examples
phpdependency-injectionnamespacesphp-di

PHP-DI: Interface being injected into constructor won't resolve correctly


I can't seem to get PHP-DI to properly resolve an interface to it's configured class when injected in the constructor. In the following code, using the container to get \Foo\IDog returns a Poodle class, but when using the container to get \Foo\Kennel (which has a \Foo\IDog in the constructor, it no longer recognizes that it's configured to return a Poodle and errors saying:

"Entry "\Foo\Kennel" cannot be resolved: Entry "Foo\IDog" cannot be resolved: the class is not instantiable"

Here's the proof of concept:

<?php
namespace Foo;

require(__DIR__ . "/vendor/autoload.php");

interface IDog {
    function bark();
}

class Poodle implements IDog {
    public function bark() {
        echo "woof!" . PHP_EOL;
    }
}

class Kennel {
    protected $dog;
    public function __construct(\Foo\IDog $dog) {
        $this->dog = $dog;
    }

    public function pokeDog() {
        $this->dog->bark();
    }
}

$containerBuilder = new \DI\ContainerBuilder();
$containerBuilder->addDefinitions([
    "\Foo\IDog" => \DI\autowire("\Foo\Poodle")
]);
$container = $containerBuilder->build();

//Works:
$mydog = $container->get("\Foo\IDog");
$mydog->bark();

//Does not work:
$kennel = $container->get("\Foo\Kennel");
$kennel->pokeDog();

The strange thing is that it works fine if I remove all namespacing from it (here it is with no namespacing: https://gist.github.com/brentk/51f58fafeee8029d7e8b1e838eca3d5b).

Any idea what I'm doing wrong?


Solution

  • I think this is because your class names are not valid in your configuration: "\Foo\IDog" is not valid, "Foo\IDog" is.

    When in code \Foo\IDog works too but when in a string only Foo\IDog is valid.

    A safe way to avoid that is to use \Foo\IDog::class. That way PHP will tell you that the class doesn't exist.