【问题标题】:Symfony service destructor called multiple times多次调用 Symfony 服务析构函数
【发布时间】:2018-12-04 10:28:25
【问题描述】:

我玩 Symfony 4 已经有一段时间了,最​​近我为我的一个网页创建了一个 twig 扩展,它负责根据数据库中的数据翻译任何给定的字符串。不幸的是,我遇到了一个我无法解决的奇怪问题。我会尝试按时间顺序写下发生的事情,这样更容易理解。

  1. DatabaseTranslateExtension 在 Twig 中注册了一个新的 |translate 过滤器。
  2. |translate 过滤器触发 延迟加载 TranslationService 被构造(当然,当它尚未构造时)。
  3. 仅创建了一个 TranslationService 实例(这是预期的)。
  4. 构造函数会预加载数据,因此不会在每次转换时都调用数据库。
  5. 过滤器调用translate方法,该方法要么翻译字符串,要么(如果数据库中没有翻译)将字符串添加到实例变量中,我们称之为stringsToTranslate,这是一种数组(@987654328 @)。
  6. 翻译完所有字符串后,应该调用服务的析构函数,这会将stringsToTranslate 数组刷新到数据库中。

我最近意识到数据库中有很多重复项,因此我尝试调试应用程序并查看发生了什么。不知何故,我什至不知道这是可能的,服务的析构函数被调用了两次,而不是一次。我很确定 Symfony 与它有关(可能是因为延迟加载)或它创建的一些反映类。我想知道是否有什么你能想到的,这会触发析构函数被调用两次(是的,它是一个类的完全相同的实例)。提前谢谢你。


我确实在构建的应用程序中跟踪了代码,并找到了为我的服务创建的包装器,它调用了 destruct,代码如下:

public function __destruct()
{
    $this->initializer2b670 || $this->valueHolder90d49->__destruct();
}

有趣的是这个__destruct也被调用了两次。似乎是因为还创建了 Reflection 类,并且这两个类都调用了 destruct。 我确实倾倒了__destructor 的尸体。第一次评估是false,这意味着它需要在valueHolder 类上调用destruct,然后再次调用它评估为true(可能也称为destruct)。很奇怪。

【问题讨论】:

  • 尽管 php 的析构函数有点不稳定。您是否考虑过在 kernel.terminate 侦听器中进行刷新?
  • 感谢您指出。我可能需要为此创建一个 EventListener,但我认为使用析构函数来做这件事是一个不错的尝试。我个人并不经常使用它们,所以我认为当我有机会并且情况需要析构函数提供的那种行为时,最终尝试它可能会很好。不过,这是一些非常奇怪的东西,我的意思是..你怎么可能两次摧毁同样的东西?没关系,再次感谢您的建议
  • 有一些关于析构函数的旧帖子被多次调用,但最近没有。通常我会说您创建了两个实例(可能通过 _profile 栏),但您表示情况并非如此。我认为这只发生在生产模式下。

标签: php symfony service destructor symfony4


【解决方案1】:

如果有人遇到类似问题,请使用KernelEvents::RESPONSEKernelEvents::TERMINATE 而不是__destructor

  • KernelEvent::RESPONSE 在发送响应之前被触发。
  • KernelEvent::TERMINATE 在响应发送后被触发。

有关 Symfony 生命周期/事件的更多信息,请访问 here


对于那些对__destruct 多次调用感到好奇的人,这可能是因为在包装器之上创建了反射类。普通类实例和反射类实例都被破坏了,我可能会这样调用它几次。

【讨论】:

    猜你喜欢
    • 2012-07-12
    • 2015-03-24
    • 2014-08-22
    • 1970-01-01
    • 2019-05-09
    • 2010-12-29
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多