这个问题与Symfony 2没有严格的关系,但是当我使用Symfony 2组件并且稍后可能使用Symfony \ Component \ DependencyInjection \ Container作为DI-Container时,它可能是相关的。
我目前正在使用Symfony 2中的组件构建一个小型库,例如: HttpFoundation,Validator,Yaml。我的域服务都扩展了一个基本的AbstractService,只提供Doctrine \ ORM \ EntityManager和Symfony \ Component \ Validator \ Validator,如下所示:
abstract class AbstractService
{
protected $em;
protected $validator;
/**
* @param Doctrine\ORM\EntityManager $em
* @param Symfony\Component\Validator\Validator $validator
*/
public function __construct(EntityManager $em, Validator $validator)
{
$this->em = $em;
$this->validator = $validator;
}
}
扩展此AbstractService的Service类现在可能需要注入其他组件,例如Symfony \ Component \ HttpFoundation \ Session。我这样做是这样的:
class MyService extends AbstractService
{
/**
* @var Symfony\Component\HttpFoundation\Session
*/
protected $session;
/**
* @param Symfony\Component\HttpFoundation\Session $session
* @param Doctrine\ORM\EntityManager $em
* @param Symfony\Component\Validator\Validator $validator
*/
public function __construct(Session $session, EntityManager $em, Validator $validator)
{
parent::__construct($em, $validator);
$this->session = $session;
}
}
有没有更优雅的方法来解决这个问题,而不必重复父的构造函数参数,例如:通过使用Setter-Injection for Session?
在我看来,当我使用Setter-Injection for Session时,我必须在我的方法中访问之前添加检查,是否已经注入,我想避免。另一方面,我不想“重复”注入所有服务共享的基本组件。
答案 0 :(得分:3)
另一种方法是不从抽象类型扩展您的服务。将抽象类型更改为真实类,然后将其注入您的服务,例如
class MyService
…
public function __construct(ServiceHelper $serviceHelper)
{
$this->serviceHelper = $serviceHelper;
}
}
另一个选择是在需要之前不传递依赖关系,例如。
class MyService
…
public function somethingRequiringEntityManager($entityManager)
{
// do something with EntityManager and members of MyService
}
}
答案 1 :(得分:1)
有没有更优雅的方法来解决这个问题,而不必重复父的构造函数参数,例如:通过使用Setter-Injection for Session?
好吧,通过像你提到的那样使用setter-injection。除此之外,我看到了立即问题的两种可能解决方案:
使父构造函数也接受Session对象,但默认情况下为null。这对我来说很难看,因为父实际上并不需要会话对象,如果你有其他实现,这将导致父构造函数的长参数列表,所以这实际上不是一个选项。
传入更抽象的对象。无论是针对特定类型对象的ParameterObject,还是仅仅是一个简单的注册表,这都应该有效。再次;不太可取,因为你正在使用依赖注入,你可能已经知道了原因。
我不得不问;使用当前方式的危害在哪里?我实际上并没有看到缺点。我会继续前进并坚持下去。如果您发现在构造函数中使用了更多参数,请考虑服务的意图是什么以及为什么需要它,可能会将特定的行为移动到您请求的对象上。
答案 2 :(得分:0)
你可以使用单例作为Session类并在任何地方访问它的实例,但是如果你想限制它的用法,那么这可能不是一个选项。
但是再次Session::getInstance()->getStuff
似乎与$this->session->getStuff
几乎相同所以回答你的问题 - 我不认为这里有很多选择,你的方法似乎很好。
哦,就像戈登说:你不应该改变论点的顺序。
答案 3 :(得分:0)
我在开发Abstract Controller Bundle时遇到了同样的问题 - 当控制器被定义为服务时 - 最终使用the base class中的setter注入。