【问题标题】:PHP-DI not able to wire interface to implementation w/ slim bridgePHP-DI 无法将接口连接到带有超薄桥的实现
【发布时间】:2019-11-11 00:19:46
【问题描述】:

我来自 .net 和 DI/IOC 容器,如 autofac、ninject 等。

我希望,php-di 的文档似乎暗示以下应该有效:

index.php / 前端控制器

$containerBuilder = new DI\ContainerBuilder();
$containerBuilder->addDefinitions([

    ListRepositoryInterface::class => DI\get(ListRepository::class)
]);

$app = DI\Bridge\Slim\Bridge::create($container);

$app->get('/list', [HelloWorldController::class, 'get']);

$app->run();

有问题的“控制器即服务”:

/*
* HelloWorldController
*/
class HelloWorldController
{
    private $listRepository;

    public function __construct(ListRepositoryInterface $listRepository)
    {
        $this->listRepository = $listRepository;
    }

    public function get(Request $request, Response $response)
    {
        $lists = $this->listRepository->getAllForUser(0);
        $json = json_encode($lists);

        $response->getBody()->write($json);

        return $response;
    }
}

接口和实现,在一个代码块中为简洁起见:

interface ListRepositoryInterface
{
    public function getAllForUser($userId);
}

class ListRepository implements ListRepositoryInterface
{
    public function getAllForUser($userId) 
    {
        return [
                [
                    'name' => 'a list'
                ]
            ];
    }
}

当我使用 php 开发服务器运行此程序并点击 <addr>/list 时,我得到(有几个换行符用于可视化和清理我的个人信息):

Fatal error: Uncaught DI\Definition\Exception\InvalidDefinition: Entry "ToDo\Controllers\HelloWorldController" cannot be resolved: Entry "Todo\DataAccess\Contracts\ListRepositoryInterface" 
cannot be resolved: the class is not instantiable Full definition: Object ( class = #NOT INSTANTIABLE# Todo\DataAccess\Contracts\ListRepositoryInterface lazy = false ) Full definition: Object ( class = ToDo\Controllers\HelloWorldController lazy = false 
__construct( $listRepository = get(Todo\DataAccess\Contracts\ListRepositoryInterface) ) ) in /Users/<user>/src/php-todo/app/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php:18 
Stack trace: #0 /Users/<user>/src/php-todo/app/vendor/php-di/php-di/src/Definition/Resolver/ObjectCreator.php(155): 
DI\Definition\Exception\InvalidDefinition::create(Object(DI\Definition\ObjectDefinition), 'Entry "ToDo\\Con...') #1 /Users/<user>/src/php-todo/app/vendor/php-di/php-di/src/Definition/Resolver/ObjectCreator.php(71): DI\Definition\Resolver\Objec in /Users/<user>/src/php-todo/app/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php on line 18

这似乎暗示我对addDefinitions 的调用没有受到任何形式的尊重。我已经尝试过DI\getDI\autowireDI\create 以及我能找到的任何其他东西......我没有额外的注册,我没有额外的任何有趣的东西。

php-di 的所有文档都说(像所有 DI 框架应该):“类型提示接口并注册要使用的具体类型”,但他们所有的 slim-bridge 示例简单地显示一个正在注入的类(这在 IMO 中用处不大)。至此 如果我将 HelloController 更改为接受 ListRepository 而不是 ListRepositoryInterface 的 ctor 参数,一切都会按预期工作。

我只是不擅长 php 并且不懂接口和类型提示吗?我是一个糟糕的 php-di 吗?我在做一些 php 开发人员会认为是疯狂的事情吗?我是否只是误解了所有内容并通过 c# 有色眼镜看它?

【问题讨论】:

  • 小更新....到目前为止,如果我将所有这些代码放入一个文件中,一切正常。这可能是某些 PSR-4 自动加载无法按我预期的那样工作的副作用吗?

标签: php dependency-injection slim php-di


【解决方案1】:

好的,这是一个带有自动加载的问题,特别是与命名空间问题有关。我正在构建一个“todo”应用程序来学习一些特定于 php 的基础知识......所以我有一个 ToDo 的根命名空间。我遵循 PSR-4 约定,但我在 Todo 的命名空间中声明了接口。

大小写不匹配导致了一些意想不到的(对我而言)行为......考虑到 php 被解释等,这是有道理的,但我没有意识到 类的实例化有多懒会的。基本上我注册的全名和实际接口的声明不匹配

我可以使用ToDo\InterfaceThing,但在src/InterfaceThing.php 文件中声明了Todo\InterfaceThing,它不会崩溃....直到它尝试将这两种类型相互匹配并看到ToDoTodo 不一样。

从本质上讲,我本来预计会出现“找不到类型错误”(Repository::class 行),但我最终注册了一个不存在的类型,因为它不存在,所以永远不会匹配 :)

【讨论】:

    【解决方案2】:

    当我对composer.json 部分"autoload": {"psr-4": { "App\\": "app" }} 进行更改并忘记执行composer dumpautoload 时,自动加载有类似问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 2018-12-30
      • 1970-01-01
      相关资源
      最近更新 更多