Symfony中基于接口的DI配置

时间:2018-07-12 19:54:35

标签: php symfony dependency-injection symfony4

在我的Symfony项目中,我将有很多具有相似依赖关系的类(但是,这些类之间并不直接相关)。例如,其中大多数都需要访问EventBus

在其他框架中,我可以为该类指定一个接口,例如:

interface EventBusAwareInterface 
{
    public setEventBus(EventBus $bus);
    public getEventBus() : EventBus
}

然后配置DI容器以识别实现此接口的此类对象,并使用适当的参数调用其setEventBus()方法。

我想知道Symfony4中是否有一种方法可以做到这一点。

3 个答案:

答案 0 :(得分:0)

是的,甚至更简单的事情也是可能的。但是,我不鼓励过度使用它,因为它会很快引入方法名称冲突之类的内容并降低代码的可读性。

也就是说,Symfony引入了以3.3开头的服务自动装配概念(我认为),该概念可用于通过零配置进行依赖注入。在PHP中,接口不能包含实现,但可以包含特征。因此,您可以执行以下操作:

trait FooTraitHandler
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

然后:

class RealService
{
    use FooTraitHandler;

    public function multiply($a, $b)
    {
        $this->logger->log(LogLevel::ALERT, "Doing some basic math!");

        return $a * $b;
    }
}   

最后,例如,您的控制器可以注入此RealService服务并照常使用multiply方法。

所以,有几件事值得一提:

  1. 您不需要一对getter / setter-特质的成员在使用它的类中可见。
  2. 您可以利用许多特征,通过许多界面来实现所需的目标
  3. 最后,如果某些利用的特征具有相同名称的方法,则会出现致命错误。根据官方文档:
  

如果两个特性插入了一个具有相同名称的方法,则如果未明确解决冲突,则会产生致命错误。要解决同一类中使用的特征之间的命名冲突,需要使用代替运算符来选择确切的一种冲突方法。

但是,我认为这样做会大大降低代码的可读性。

希望这对您有帮助...

答案 1 :(得分:0)

我的原始评论不正确。您可以使用@inject,但似乎需要附加的jms捆绑包。本来可以宣誓支持该容器的容器,但我想不是。

但是,autowire支持@required annotation似乎可以解决问题。

use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;

trait RouterTrait
{
    /** @var RouterInterface */
    protected $router;

    /**
     * @param RouterInterface $router
     * @required
     */
    public function setRouter(RouterInterface $router)
    {
        $this->router = $router;
    }
    // Copied directly from Symfony ControllerTrait
    protected function generateUrl(
        string $route,
        array $parameters = array(),
        int $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string
    {
        return $this->router->generate($route, $parameters, $referenceType);
    }
    protected function redirect($url, $status = 302) : RedirectResponse
    {
        return new RedirectResponse($url, $status);
    }
    protected function redirectToRoute($route, array $parameters = array(), $status = 302) : RedirectResponse
    {
        return $this->redirect($this->generateUrl($route, $parameters), $status);
    }

}

现在,任何使用RouterTrait的自动接线服务都将自动注入路由器。

答案 2 :(得分:0)

您可以像这样在_instanceof中使用services.yaml指令:

services:
  _instanceof:
    App\EventBusAwareInterface:
      calls:
        - method: setEventBus
          arguments:
            - '@event.bus.service'