多次调用 Symfony 服务析构函数
Symfony service destructor called multiple times
我已经使用 Symfony 4 一段时间了,最近我为我的一个网页创建了一个 twig 扩展,它负责根据数据库中的数据翻译任何给定的字符串。不幸的是,我遇到了一个我无法解决的奇怪问题。我会尝试按时间顺序写下发生的事情,这样更容易理解。
DatabaseTranslateExtension
在 Twig 中注册了一个新的 |translate
过滤器。
|translate
过滤器触发一个 延迟加载 TranslationService
被构建(当然,当它还没有被构建时)。
- 只创建了一个
TranslationService
实例(这是预期的)。
- 构造函数预加载数据,因此它不会在每次发生转换时调用数据库。
- 过滤器调用
translate
方法,该方法要么翻译字符串,要么(如果数据库中没有翻译)将字符串添加到实例变量中,我们称它为 stringsToTranslate
,这是一个数组类型 (String[]
).
- 翻译完所有字符串后,应调用服务的 析构函数 ,这会将
stringsToTranslate
数组刷新到数据库中。
我最近意识到我在数据库中有很多重复项,所以我尝试调试应用程序并查看发生了什么。不知何故,我什至不知道这是可能的,服务的析构函数被调用了两次,而不是一次。我很确定 Symfony 与它有关(这可能是因为延迟加载)或一些反映它创建的 classes。我想知道您是否能想到任何可以触发析构函数被调用两次的方法(是的,它是 class 的完全相同的实例)。提前谢谢你。
我确实在一个构建的应用程序中找到了代码,并找到了为我的服务创建的包装器,它调用了一个破坏,这是代码:
public function __destruct()
{
$this->initializer2b670 || $this->valueHolder90d49->__destruct();
}
有意思的是这个__destruct
也被调用了两次。似乎是因为还创建了 Reflection class 并且 classes 都调用了 destruct。
我确实抛弃了 __destructor
的尸体。第一次评估是 false
,这意味着它需要在 valueHolder
class 上调用 destruct 然后再次调用它评估为 true
(可能也称为 destruct ).奇怪。
如果有人遇到类似问题,请使用 KernelEvents::RESPONSE
或 KernelEvents::TERMINATE
而不是 __destructor
。
KernelEvent::RESPONSE
在发送响应之前触发。
KernelEvent::TERMINATE
发送响应后触发。
有关 Symfony 的 lifecycle/events 的更多信息,请参见 here。
对于多次调用 __destruct
感到好奇的人,这可能是因为在包装器之上创建的反射 class。正常的 class 实例和反射的 class 实例被破坏了我可能会调用它几次。
旧线程,但最近遇到了同样的问题,因此提供反馈以防其他人遇到类似问题。
在我的例子中,它在 Command
中调用 __destruct
。
我最终 __destruct
被调用了 6 次。我遵循了反射被破坏等的想法。但这与 Symfony 本身有关。
为什么我这么认为?因为它在启动时表现相似 - 它加载所有命令,调用它们的 __construct
(尝试将 echo
添加到每个 Command::__construct
然后调用 bin/console about
,你会看到所有 echo
都被调用。)
Symfony 为我得到的每个 Command
调用了 __destruct
。
为了防止这种情况,我不得不在主 AbstractCommand
中调用 execute
(我的 class 所有命令都从中扩展),创建了:
protected abstract doExecute():void;
然后我在 AbstractCommand::execute
中调用 doExecute
,然后在 execute
的最后我添加了对我在 _destruct
中的逻辑的调用。
我已经使用 Symfony 4 一段时间了,最近我为我的一个网页创建了一个 twig 扩展,它负责根据数据库中的数据翻译任何给定的字符串。不幸的是,我遇到了一个我无法解决的奇怪问题。我会尝试按时间顺序写下发生的事情,这样更容易理解。
DatabaseTranslateExtension
在 Twig 中注册了一个新的|translate
过滤器。|translate
过滤器触发一个 延迟加载TranslationService
被构建(当然,当它还没有被构建时)。- 只创建了一个
TranslationService
实例(这是预期的)。 - 构造函数预加载数据,因此它不会在每次发生转换时调用数据库。
- 过滤器调用
translate
方法,该方法要么翻译字符串,要么(如果数据库中没有翻译)将字符串添加到实例变量中,我们称它为stringsToTranslate
,这是一个数组类型 (String[]
). - 翻译完所有字符串后,应调用服务的 析构函数 ,这会将
stringsToTranslate
数组刷新到数据库中。
我最近意识到我在数据库中有很多重复项,所以我尝试调试应用程序并查看发生了什么。不知何故,我什至不知道这是可能的,服务的析构函数被调用了两次,而不是一次。我很确定 Symfony 与它有关(这可能是因为延迟加载)或一些反映它创建的 classes。我想知道您是否能想到任何可以触发析构函数被调用两次的方法(是的,它是 class 的完全相同的实例)。提前谢谢你。
我确实在一个构建的应用程序中找到了代码,并找到了为我的服务创建的包装器,它调用了一个破坏,这是代码:
public function __destruct()
{
$this->initializer2b670 || $this->valueHolder90d49->__destruct();
}
有意思的是这个__destruct
也被调用了两次。似乎是因为还创建了 Reflection class 并且 classes 都调用了 destruct。
我确实抛弃了 __destructor
的尸体。第一次评估是 false
,这意味着它需要在 valueHolder
class 上调用 destruct 然后再次调用它评估为 true
(可能也称为 destruct ).奇怪。
如果有人遇到类似问题,请使用 KernelEvents::RESPONSE
或 KernelEvents::TERMINATE
而不是 __destructor
。
KernelEvent::RESPONSE
在发送响应之前触发。KernelEvent::TERMINATE
发送响应后触发。
有关 Symfony 的 lifecycle/events 的更多信息,请参见 here。
对于多次调用 __destruct
感到好奇的人,这可能是因为在包装器之上创建的反射 class。正常的 class 实例和反射的 class 实例被破坏了我可能会调用它几次。
旧线程,但最近遇到了同样的问题,因此提供反馈以防其他人遇到类似问题。
在我的例子中,它在 Command
中调用 __destruct
。
我最终 __destruct
被调用了 6 次。我遵循了反射被破坏等的想法。但这与 Symfony 本身有关。
为什么我这么认为?因为它在启动时表现相似 - 它加载所有命令,调用它们的 __construct
(尝试将 echo
添加到每个 Command::__construct
然后调用 bin/console about
,你会看到所有 echo
都被调用。)
Symfony 为我得到的每个 Command
调用了 __destruct
。
为了防止这种情况,我不得不在主 AbstractCommand
中调用 execute
(我的 class 所有命令都从中扩展),创建了:
protected abstract doExecute():void;
然后我在 AbstractCommand::execute
中调用 doExecute
,然后在 execute
的最后我添加了对我在 _destruct
中的逻辑的调用。