I've been playing with Symfony 4 for a while now and I've created a twig extension for one of my webpages recently, which is responsible for translating any given string based on data in database. Unfortunately, I've faced with a weird problem which I cannot resolve. I'll try to write down what happens chronologically, so it's more understandable.
- The
DatabaseTranslateExtension
registers a new|translate
filter in Twig. |translate
filter triggers a lazy-loadedTranslationService
to be constructed (when it's not constructed yet, of course).- There's only one instance of
TranslationService
created (which is expected). - Constructor preloads the data, so it's not calling the database every time translation happens.
- The filter calls
translate
method, which either translates the string or (if there's no translation in the database) adds the string into an instance variable, let's call itstringsToTranslate
, which is a type of array (String[]
). - After all strings have been translated, the service's destructor should be called, which does flush the
stringsToTranslate
array into a database.
I recently realized that I have many duplicates in the database, so I tried to debug the app and see what's happening. Somehow, I had no idea it's even possible, the service's destructor is called twice, not once. I'm pretty sure Symfony has something to do with it (it might be because the lazy loading) or some reflect classes it creates. I'm wondering if there's anything you can think of, which would trigger the destructor to be called twice (Yes, it's the exact same instance of a class). Thank you in advance.
I did track the code down in a built app and found the wrapper created for my service, which calls a destruct, here's the code:
public function __destruct()
{
$this->initializer2b670 || $this->valueHolder90d49->__destruct();
}
What's interesting is that this __destruct
is also called twice. It seems like it's because there's also Reflection class created and both classes call destruct.
I did dump the __destructor
's body. First evaluation was false
, which means it needed to call a destruct on the valueHolder
class and then it gets called once again what evaluated to true
(that probably called destruct too). Weird.