我一直在整个PHP应用程序中练习构造函数依赖注入。我不想在创建对象时乱丢我的代码,所以工厂要救援,或者至少我想过。
我开始与工厂连接组件,然后一些工厂开始使用其他工厂来获取依赖关系,很棒,将所有创建代码保存在一个地方。但是,一旦工厂开始互相使用(或者如下面的代码本身),我遇到了循环依赖问题,这根本无法解决。例如,我的MapperFactory使用自己将mappers与其他映射器一起注入(它们需要彼此构建一个完整的对象图''eager loading'):
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)。
我的问题是,我是否完全错过了工厂的观点?我正确使用工厂吗?它似乎不是,但除了循环依赖(非常重要但是)之外,工厂是一种优雅的解决方案,可以将所有构造/布线逻辑隐藏在主应用之外。
答案 0 :(得分:1)
您可以尝试使用setter注入依赖项。然后你就像这样创建两个映射器:
$itemMapper = new Mapper();
$fieldMapper = new Mapper();
$itemMapper->setRelatedMapper($fieldMapper);
$fieldMapper->setRelatedMapper($itemMapper);
然后使用开关返回映射器。这应该在创建对象时摆脱循环依赖。
话虽如此,如果你把它作为一种连接到数据库的OR / M的东西,你应该看看像Doctrine2或Propel这样的东西,只是为了省去发明轮子的麻烦。已经经过试验和测试的解决方案。
答案 1 :(得分:0)
看起来MapperFactory
的{{1}}方法导致无限循环。
create
如果交换机正在寻找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,
);
匹配,则case操作必须是布尔值
TRUE