【问题标题】:Dependency Injection with factories工厂的依赖注入
【发布时间】:2012-08-09 23:15:49
【问题描述】:

我一直在整个 PHP 应用程序中练习构造函数依赖注入。我不想在我的代码中乱扔对象创建,所以工厂来救援,或者至少我是这么认为的。

我开始用工厂连接组件,然后一些工厂开始使用其他工厂来获取依赖项,太好了,将所有创建代码保存在一个地方。但是,一旦工厂开始相互使用(或在下面的代码中,本身),我遇到了循环依赖问题,这根本无法解决。例如,我的 MapperFactory 使用自己将映射器与其他映射器注入(它们需要彼此构建完整的对象图“急切加载”):

class MapperFactory
{   
    public function create($type)
    {
        switch (true) {
            case 'Item':
                $mapper = new ItemMapper(
                    $this->create('Field')  
                );               
                break;
            case 'Field':
                $mapper = new ItemMapper(
                    $this->create('Item')  
                );
                break;
            default:
                throw new Exception('Unknown mapper');
        }
        return $mapper;
    }

}

$mf = new MapperFactory();
$mf->create('Item');

这是一个简化的示例,但随着应用程序的开发,这是一个越来越普遍的问题。从 PHP(安装了 xdebug)返回的错误是:

Fatal error: Maximum function nesting level of '100' reached, aborting!

完全理解 PHP 抱怨的原因(虽然 TBH 没看到)。

我的问题是,我是否完全忽略了工厂的意义?我是否正确使用工厂?看起来不是,但除了循环依赖(相当重要)之外,工厂是一种优雅的解决方案,可以将所有构造/连接逻辑隐藏在主应用程序之外。

【问题讨论】:

  • 我认为这不是工厂的问题。首先,我没有得到“开关(真)”部分。那不应该是“switch ($type)”吗?其次,您的代码(如果我没看错的话)会无休止地递归。也许您应该只在准备好使用该实例变量时才创建子字段或子项。或者想出一些东西来结束递归。
  • 我猜switch (true) ... 不是你要写的。但即使使用switch ($type),如果$typeFieldItem,你也会得到一个无限循环。

标签: php dependency-injection factory


【解决方案1】:

看起来MapperFactorycreate 方法会导致无限循环。

switch(true) {
  case 'Item' : // this will always be selected http://php.net/manual/en/language.types.type-juggling.php
    $mapper = new ItemMapper(
      $this->create('Field'); // Forces loop,
    );

如果 switch 正在寻找 TRUE 匹配,那么 case 操作必须是布尔值

switch(true) {
  case $type == 'Item' :
    // ...
    break;
  case $type == 'Field' :
    // ...
 }

【讨论】:

  • 是的,对不起,鉴于问题的上下文(循环依赖),这是不可原谅的。应该是 switch($type)。
【解决方案2】:

您可以尝试使用 setter 来注入依赖项。然后你会像这样创建两个映射器:

$itemMapper = new Mapper();
$fieldMapper = new Mapper();
$itemMapper->setRelatedMapper($fieldMapper);
$fieldMapper->setRelatedMapper($itemMapper);

然后使用 switch 只是返回映射器。这应该在创建对象时摆脱循环依赖。

话虽如此,如果您将其作为一种 OR/M 操作来连接到数据库,您可能应该研究 Doctrine2 或 Propel 之类的东西,只是为了省去自己发明轮子的麻烦。已经尝试和测试过的解决方案。

【讨论】:

  • 是的,我尝试过设置器,尽管将依赖项视为“要求”,因此在构造函数中需要它们。但绝对是我必须再看一遍的东西。 ORM 方面,我还需要通过 SOAP 和 REST 服务来持久化对象,因此需要保持灵活性。
  • 是的,构造函数是一种强制关系的方式,但在您的示例中,它创建了一个循环,因为“item”创建了“field”,它创建了“item”等等......通过使用 setter,您只需在对象之间共享引用,虽然 var dump 或类似的东西也会显示无限的对象层次结构,但至少它不会中断。而且您只创建了两个实例,而不是无穷大......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
  • 1970-01-01
相关资源
最近更新 更多