php - 使用 Symfony 自动装配扩展类的正确方法
问题描述
我想知道这是否是使用 Symfonys 自动装配扩展和使用类的正确方法。
例如,我有一个 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);
}
}
现在我想知道这是否真的是正确的方法,还是我缺少一些东西,父类应该能够自行自动装配实体管理器?
解决方案
总结评论,是的,你的方式是正确的。根据您的用例,有替代方案。
这是您可以解决的方法:
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;
}
}
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;
}
}
现在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;
}
3.属性注入
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
public $other;
}
与 Setter 注入一样,您需要告诉 Symfony 填充此属性,方法是在services.yaml
文件中指定它,如下所示:
// services.yaml
App\SubClass:
properties:
other: '@other'
或者
// services.yaml
app.sub_class:
class: App\SubClass
properties:
other: '@other'
假设,在服务容器中的实现OtherInterface
是可用的。@other
结论:
由于有不同的方法可以解决这个问题,因此您可以为您的用例确定正确的方法。我个人使用注释选择选项 1(构造函数注入)或选项 2(Setter 注入)。它们都允许您使用类型提示,从而允许您的 IDE 帮助您编写干净的代码。
在 90% 的情况下,我会选择选项 1,因为这样对于每个阅读您的代码的人来说,一眼就可以清楚地了解该__constructor
功能可以使用哪些服务。
Setter 注入的一个用例是提供所有setXXX
功能的基类,但子类不需要所有功能。您可以在每个子类中都有一个构造函数,请求所需的服务,然后调用setXXX
基类的方法。
注意:这是一种边缘情况,您可能不会遇到这种情况。
您可以直接在 Symfony 文档中找到关于服务容器 -> 注入类型的每种方法的优缺点列表
推荐阅读
- c# - 拆分字符串并按顺序保持分隔符
- cloudflare-apps - 在预览 Cloudflare 应用程序时,之前存储的 cookie 开始发挥作用
- php - 在 PHP 中显示 SQL 中的记录总数
- hadoop - 使用 ORC serde 时在 hive 中创建表属性的差异
- html - CSS 内容未在 Chrome 和 Opera 上显示
- facebook - 每次登录游戏时,Unity Facebook SDK 都会不断要求我确认登录
- c# - 具有两个不同版本的 ODAC 的 InvalidCastException
- node.js - Node-js:sendgrid - 无法创建生产版本
- spring - Spring Security + JWT:登录成功后如何丰富Authentication/Principal?
- mysql - 如何获得总和(具体)