Dear all, Le mar. 16 juil. 2024 à 17:51, Nicolas Grekas <nicolas.grekas+...@gmail.com> a écrit :
> Hi there, > > Le mar. 16 juil. 2024 à 10:13, Nicolas Grekas < > nicolas.grekas+...@gmail.com> a écrit : > >> >> >> Le lun. 15 juil. 2024 à 21:42, Tim Düsterhus <t...@bastelstu.be> a écrit : >> >>> Hi >>> >>> On 7/15/24 09:25, Nicolas Grekas wrote: >>> > Testing is actually a good domain where resetting lazy objects might >>> open >>> > interesting use cases. >>> > This reminded me about zenstruck/foundry, which leverages the >>> > LazyProxyTrait to provide refreshable fixture objects >>> > < >>> https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#auto-refresh >>> > >>> > and provides nice DX thanks to this capability. >>> > >>> >>> I have not used this library before, but I have taken a (very) brief >>> look at the code and documentation. >>> >>> My understanding is that all the fixture objects are generated by a >>> corresponding Factory class. This factory clearly has the capability of >>> constructing objects by itself, so it could just create a lazy proxy >>> instead? >>> >>> I'm seeing the `instantiateWith()` example in the documentation where >>> the user can return a constructed object themselves, but I'm not seeing >>> how that can safely be combined with the `reset*()` methods: Anything >>> special the user did to construct the object would be reverted, so the >>> user might as well rely on the default construction logic of the factory >>> then. >>> >>> What am I missing? >>> >> >> Finding the spot where the reset method would be useful is not easy. Here >> it is: >> >> https://github.com/zenstruck/foundry/blob/v2.0.7/src/Persistence/IsProxy.php#L66-L76 >> >> Basically, the reset method is not needed when creating the lazy proxy. >> But it's needed to refresh it when calling $object->_refresh(). The >> implementation I just linked swaps the real object bound to the proxy for >> another one (the line >> "Configuration::instance()->persistence()->refresh($object);" swaps by >> reference). >> > > > After chatting a bit with Benjamin on Slack, I realized that the sentence > "The indented use-case is for an object to manage its own laziness by > calling the method in its constructor" was a bit restrictive and that there > are more use cases for reset methods. > > Here is the revised part about resetAsLazyGhost in the RFC: > > This method allows an object to manage its own laziness by calling the > method in its constructor, as demonstrated here > <https://gist.github.com/arnaud-lb/9d52e2ba4e278411bff3addf75ce56be>. In > such cases, the proposed lazy-object API can be used to achieve lazy > initialization at the implementation detail level. > > Another use case for this method is to achieve resettable services. In > these scenarios, a service object already inserted into a complex > dependency graph can be reset to its initial state using the lazy object > infrastructure, without its implementation being aware of this concern. A > concrete example of this use case is the Doctrine EntityManager, which can > end up in a hard to recover <https://github.com/doctrine/orm/issues/5933> > "closed" state, preventing its use in long-running processes. However, thanks > to the lazy-loading code infrastructure > <https://github.com/symfony/symfony/blob/1a16ebc32598faada074e0af12a6a698d2964a5e/src/Symfony/Bridge/Doctrine/ManagerRegistry.php#L42>, > recovering from such a state is possible. This method would be instrumental > in achieving this capability without resorting to the current complex code > used in userland. > > I hope this helps. > A bit unrelated to the above topic: we've further clarified the RFC by addition restrictions to what can be done with lazy proxies. Namely, when the factory returns an object from a parent class, we describe that adding more on the proxy class would throw, and we also explain why. We also added a restriction to prevent a proxy from having an overridden __clone or __destruct when the factory returns a parent, and explained why again. This should simplify the overall behavior by preventing edge case that wouldn't have easy answers. If those limitations prove too restrictive in practice (my experience tells me they should be fine), they could be leveraged in the future. On our side, this should close the last topics we wanted to address before opening the vote. Please let us know if anyone has other concerns. Cheers, Nicolas