On Wed, Jul 17, 2024, at 20:31, Nicolas Grekas wrote:
> Dear all,
> 
> Le mar. 16 juil. 2024 à 17:51, Nicolas Grekas <nicolas.grekas+...@gmail.com 
> <mailto:nicolas.grekas%2b...@gmail.com>> a écrit :
>> Hi there,
>> 
>> Le mar. 16 juil. 2024 à 10:13, Nicolas Grekas <nicolas.grekas+...@gmail.com 
>> <mailto:nicolas.grekas%2b...@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

If you cannot use an instance of a subclass as the actual object, then it the 
methods probably shouldn't exist on ReflectionClass since you use that to 
reflect on interfaces and abstract classes. This also limits the usability, as 
for example, in a container, you might know that the type you need to return is 
MyInterface, but not know what type the actual factory will return.

— Rob

Reply via email to