【问题标题】:Dependency Injection : DIY Container or Framework?依赖注入:DIY容器还是框架?
【发布时间】:2017-10-10 18:14:38
【问题描述】:

在过去的几天里,我一直在阅读大量有关依赖注入的文章,并且一直在使用 Aura.DI 来玩一下 IoC 原则。在实施此模式时,我遇到了一些我听说很常见的问题,但我仍然不太确定其中的一些细节。

如果我想将记录器(比如 Monolog)注入控制器类(只是一个简单的示例),据我所知,我想使用类名作为日志记录通道(基本上是 new Logger('somecontroller')) ,这意味着为每个班级手动定义“注入”,我这样想对吗?

这个:

$controller = new PageController(new Logger('PageController'));

在 Aura.DI 中,将是:

$di->params['PageController'] = [
    'logger' => $di->lazyNew('Logger', ['name' => 'PageController'])
];

但我必须为 每个 我想要不同日志记录通道的控制器执行此操作?!我听说你可以在这里使用抽象工厂模式,但我不确定这会如何工作? (我了解工厂模式,但从来没有遇到过我认为它会对我有所帮助的情况。虽然抽象工厂模式对我来说是新的)

我知道我可以编写一个简单的方法来迭代控制器数组并以一种不那么冗长的方式执行此操作,但这样做确实感觉有点不对。

我也遇到过this post on reddit,觉得有点道理。如果无论如何我都必须手动配置所有这些依赖项,为什么不让我的配置成为实际的实现呢?当依赖关系树变大一点时,这可能会分崩离析?不过,我认为值得询问人们的意见。

编辑:只是mocked up an example DIY 方法的工作原理,实际上看起来还不错……想法? (可能应该将很多这些方法设为私有,但你明白了)。

如果您能就我的任何/所有问题提供任何启发,我们将不胜感激。

【问题讨论】:

  • 您是否尝试过使用 Symfony DI component
  • 我没有专门尝试过这种实现,但我确实简要地通读了一遍。它看起来与 Aura.DI 实现相似(功能方面)。所以以上几点仍然是我对任一框架的疑问。
  • 您创建了什么 AbstractController,添加 Logger 作为依赖项并从该抽象控制器派生所有其他控制器?
  • 我可以这样做,但这样我每次都会得到相同的 Logger 实例。我想要一个新的记录器实例,这样我就可以有不同的“通道”(正如 Monolog 中所说的那样)来分离我的日志。这就是我面临的问题的症结所在。
  • 如果在AbstractController中添加Logger,然后在每个派生的Controller构造函数中配置呢?

标签: php design-patterns dependency-injection auraphp


【解决方案1】:

您可以通过几种不同的方式做到这一点。

  1. LoggerFactory 类注入PageController

    class PageController
    {
    
        public function __construct(LoggerFactory $loggerFactory)
        {
            $this->loggerFactory = $loggerFactory;
        }
    
        public function someAction()
        {
            $this->loggerFactory->newInstance(__CLASS__);
        }
    }
    
    class LoggerFactory
    {
        public function newInstance($name)
        {
            return new Logger($name);
        }
    }
    
  2. 使用同一LoggerwithName()。可能这是更容易的一个。您注入记录器并调用$newlogger = $this->logger->withName(__CLASS__); 并获取克隆的新实例。

  3. 使用Instance Factories

这里ExampleNeedsFactoryPageControllerExampleStructLogger

$di->params['PageController']['loggerFactory'] = $di->newFactory('Logger');

    class PageController
    {

        public function __construct(LoggerFactory $loggerFactory)
        {
            $this->loggerFactory = $loggerFactory;
        }

        public function someAction()
        {
            $logger = $this->getLogger();
        }

        public function getLogger()
        {
            $this->loggerFactory->__invoke(__CLASS__);
        }
    }

注意:在这种情况下,getLogger 总是返回新的记录器。如果您需要相同的实例,请设置记录器。

public function getLogger()
{
    if (! $this->logger) {
        $this->logger = $this->loggerFactory->__invoke(__CLASS__);
    }

    return $this->logger;
}

您还可以将这些方法移动到AbstractController 类,这样您就不需要每次都编写需要注入控制器的内容。 (@camel_case 在他的 cmets 中确实提到了这一点)

Aura.Di 也有自动解析功能,可以不用写很多配置。

希望有帮助!

【讨论】:

  • 感谢您的回答,哈里。我对它投了赞成票,但我的低代表妨碍了它正确显示。 withName 方法看起来是该特定示例的好方法,感谢您指出。我在 Aura.DI 中使用了自动连接功能,它很好,只是当你遇到这样的问题时,它并没有比我写的 DIY 方法更有帮助。如果可以的话,您能否分享您对使用 DI 框架相对于我展示的 DIY 版本的主要优势的看法,以及两种方法的优缺点?谢谢
猜你喜欢
  • 1970-01-01
  • 2014-09-06
  • 2010-09-22
  • 2010-09-14
  • 1970-01-01
  • 2018-06-15
  • 1970-01-01
  • 2016-12-06
  • 2016-08-19
相关资源
最近更新 更多