我想知道这是否是通过Symfonies自动装配扩展和使用类的正确方法。
例如,我有一个BaseClass实例化并自动连接实体管理器。
class BaseClass
{
protected $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
protected function someMethodIWantToUse(Entity $something)
{
// Do something there
$this->entityManager->persist($something);
$this->entityManager->flush();
}
}
然后,我有一个扩展BaseClass的子类,需要访问该方法。因此,我让它再次自动装配并传递给父构造函数。
class SubClass extends BaseClass
{
private $handler;
public function __construct(EntityManagerInterface $em, SomeHandler $handler)
{
parent::__construct($em);
$this->handler = $handler;
}
public function SubClassMethod()
{
// Get some data or do something
$entity = SomeEntityIGot();
$this->someMethodIWantToUse($entity);
}
}
现在,我想知道这是否是执行此操作的正确方法,或者我缺少某些东西,并且父类应该能够自行自动连接entitymanager?
总结评论,是的,您的方法是正确的。根据您的用例,有其他选择。
这是您可以使用的方法:
1。扩展类并使用Constructor Injection(您的操作)
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
private $other;
public function __construct(SomeInterface $some, OtherInterface $other)
{
parent::__construct($some);
$this->other = $other;
}
}
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
private $other;
public function setOther(OtherInterface $other)
{
$this->other = $other;
}
}
现在setOther
将不会自动被调用,您必须通过在calls
文件中指定services.yaml
属性来“手动”调用它,如下所述:https://symfony.com/doc/current/service_container/calls.html。然后看起来像这样:
// services.yaml
App\SubClass:
calls:
- [setOther, ['@other']]
或
// services.yaml
app.sub_class:
class: App\SubClass
calls:
- [setOther, ['@other']]
假定,OtherInterface
的实现可在服务容器中作为@other
使用。
[如果您使用的是自动装配,则是一个更优雅的解决方案,只需在此函数中添加@required
批注,如下所述:https://symfony.com/doc/current/service_container/autowiring.html#autowiring-calls,如下所示:
/**
* @required
*/
public function setOther(OtherInterface $other)
{
$this->other = $other;
}
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
public $other;
}
与Setter Injection一样,您需要通过在services.yaml
文件中指定该属性来告诉Symfony填充此属性:
// services.yaml
App\SubClass:
properties:
other: '@other'
或
// services.yaml
app.sub_class:
class: App\SubClass
properties:
other: '@other'
假设,OtherInterface
的实现可在服务容器中作为@other
使用。
结论:由于有多种方法可以解决此问题,因此您需要确定用例的正确方法。我个人使用注释使用选项1(构造函数注入)或选项2(Setter注入)。它们都允许您使用typehints,从而使您的IDE可以帮助您编写简洁的代码。在90%的情况下,我会选择选项1,因为这样一来,对于每个阅读您的代码的人来说,一目了然__constructor
函数可以提供哪些服务。Setter注入的一个用例是提供所有setXXX
函数的基类,但是子类不需要全部。您可以在每个子类中都有一个构造函数,请求所需的服务,然后调用基类的setXXX
方法。注意:这是一种极端情况,您可能不会遇到这种情况。
您可以直接在有关Service Container -> Types of Injection的Symfony文档中找到每种方法的优缺点列表>