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?
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.