【问题标题】:Partial dependency injection部分依赖注入
【发布时间】:2017-04-28 15:43:33
【问题描述】:

在 MVC 上下文中,我有一个依赖于服务的控制器,该服务又依赖于 data_source(在特定情况下,客户端从第三方 API 获取数据)。

为了在测试时使用模拟数据源实例化服务,服务的构造函数需要一个数据源。 控制器也是如此,它的构造函数需要一个服务。

在创建控制器时,我也想向它传递一个请求对象,因为我更喜欢这个

new Controller(request, service).action_name

到这里

new Controller(service).action_name(request)

在不使用任何容器进行依赖注入的情况下实现这一点是微不足道的。

我不明白如何使用php-di

我的目标是通过容器将服务注入控制器,同时自己将请求对象传递给控制器​​。

更新 1

这是我的应用控制器

namespace DEC;


class ApplicationController {

    private $service;
    private $request;

    public function __construct(Foo $service, $request) {
        $this->service= $service;
        $this->request = $request;
    }


    public function index() {
        $out = $this->service->foo();
        $out .= $this->request->method();
        return $out;
    }

}

Foo 跟随

namespace DEC;

class Foo {

    public function __construct() {
    }

    public function foo() {
        return "FOO";
    }
}

这是我的要求

namespace DEC;

class Foo {

    public function __construct() {
    }

    public function foo() {
        return "FOO";
    }
}

这是我尝试让 DI 按我的意愿工作:

$container = ContainerBuilder::buildDevContainer();
$response = $container->call([ApplicationController::class, 'index'], [
            'request' => new Request('GET')
]);
echo $response;

这是我得到的错误:

Entry "DEC\ApplicationController" cannot be resolved: Parameter $request of __construct() has no value defined or guessable
Full definition:
Object (
    class = DEC\ApplicationController
    scope = singleton
    lazy = false
    __construct(
        $service = get(DEC\Foo)
        $request = #UNDEFINED#
    )
)

注意:如果我键入提示请求和/或在构造函数中切换参数顺序,则错误保持不变

查看错误,我推断 Matthew Napoli 提出的 ::call() 解决方案在我仅使用服务实例化控制器并将请求作为操作方法的参数传递时有效。

这是否意味着我不能依赖容器进行“部分”注入?

更新 2

对于本次更新中描述的解决方案,请看我自己对问题的回答

【问题讨论】:

  • 有什么理由要使用 php-di?它确实使用反射(慢)。您只需将一些第 3 方“黑魔法”添加到您的项目中。您实际上要节省多少打字?只是我的恕我直言。
  • @E_p 没有性能损失,一切都被缓存了。如果不喜欢反射,你也可以禁用它:php-di.org/doc/autowiring.html#configuration
  • 我的代码库很小,我预计不会出现可衡量的性能问题。我选择了 php-di,因为它在 GitHub 上拥有近 1000 名订阅者并且正在积极维护

标签: php dependency-injection php-di


【解决方案1】:

不清楚你尝试了什么,但这应该调用 action 方法并将请求传递给它(并解析控制器及其所有依赖项):

$container->call([MyController::class, 'action_name'], [
    'request' => $request,
]);

在此处阅读有关call() 的更多信息:http://php-di.org/doc/container.html#call

【讨论】:

    【解决方案2】:

    关于请求:

    不要键入提示 $request 参数:

    public function __construct($request, /*...*/) {}
    

    或者为它键入一个 RequestInterface:

    public function __construct(RequestInterface $request, /*...*/) {}
    

    在这两种情况下,DIC 都无法自动创建请求实例。然后你可以自己注入它。

    关于服务:

    使用具体的类型提示它,例如“服务”。然后 DIC 将自动创建一个服务实例,以及它的所有依赖项(data_source)。

    或使用接口类型提示它,例如“ServiceInterface”,并在 DIC 中为它设置一个条目,使用 PHP 定义中的别名。像这样的:

    return [
        'ServiceInterface' => DI\get('<NAMESPACE-TO>\Service'),
    ];
    

    见:

    PHP-DI“限制”http://php-di.org/doc/autowiring.html#limitations

    PHP-DI “PHP 定义 - 别名”http://php-di.org/doc/php-definitions.html#aliases

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      我设法通过在请求控制器之前在容器中设置我的请求来做到这一点:

      $container->set('DEC\Request', new Request('GET'));
      $controller = $container->get('DEC\ApplicationController');
      $response = $controller->index();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-28
        • 2011-04-08
        • 2014-06-12
        相关资源
        最近更新 更多