我想知道这是否是通过 Symfony 自动装配扩展和使用类的正确方法。
例如,我有一个 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();
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有一个扩展 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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我想知道这是否真的是正确的方法,还是我遗漏了什么,父类应该能够自己自动装配实体管理器?
总结评论,是的,你的方式是正确的。根据您的用例,有替代方案。
以下是您可以采取的方法:
1. 扩展类和使用构造函数注入(你做什么)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
2.二传手注入
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;
}
}
Run Code Online (Sandbox Code Playgroud)
现在setOther
不会自动调用,您必须通过calls
在services.yaml
文件中指定属性来“手动”调用它,如下所述:https : //symfony.com/doc/current/service_container/calls.html。这看起来像这样:
// services.yaml
App\SubClass:
calls:
- [setOther, ['@other']]
Run Code Online (Sandbox Code Playgroud)
或者
// services.yaml
app.sub_class:
class: App\SubClass
calls:
- [setOther, ['@other']]
Run Code Online (Sandbox Code Playgroud)
假设在服务容器中OtherInterface
可以使用的实现@other
。
如果您使用自动装配,一个更优雅的解决方案是简单地@required
向函数添加一个注释,如下所述:https : //symfony.com/doc/current/service_container/autowiring.html#autowiring-calls,如下所示:
/**
* @required
*/
public function setOther(OtherInterface $other)
{
$this->other = $other;
}
Run Code Online (Sandbox Code Playgroud)
3.财产注入
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
public $other;
}
Run Code Online (Sandbox Code Playgroud)
与 Setter 注入一样,您需要告诉 Symfony 填充此属性,方法是在您的services.yaml
文件中指定它,如下所示:
// services.yaml
App\SubClass:
properties:
other: '@other'
Run Code Online (Sandbox Code Playgroud)
或者
// services.yaml
app.sub_class:
class: App\SubClass
properties:
other: '@other'
Run Code Online (Sandbox Code Playgroud)
假设在服务容器中OtherInterface
可以使用的实现@other
。
结论:
由于有不同的方法可以解决此问题,因此您可以为您的用例确定正确的方法。我个人选择使用注释的选项 1(构造函数注入)或选项 2(Setter 注入)。它们都允许您使用类型提示,从而允许您的 IDE 帮助您编写干净的代码。
在 90% 的情况下,我会选择选项 1,因为这样一来,每个阅读您代码的人都可以一目了然地了解哪些服务可用__constructor
。
Setter 注入的一个用例是提供所有setXXX
功能的基类,但子类不需要所有这些功能。您可以在每个子类中有一个构造函数,请求所需的服务,然后调用setXXX
基类的方法。
注意:这是一种边缘情况,您可能不会遇到这种情况。
您可以直接在有关服务容器的 Symfony 文档-> 注入类型中找到每种方法的优缺点列表
归档时间: |
|
查看次数: |
1027 次 |
最近记录: |