Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:124460 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 4971C1A00B7 for ; Wed, 17 Jul 2024 18:31:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1721241169; bh=kDByDKqxMBKzsYPFVsufg6saRE+OtLI/JWhohy+S1jM=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=i7dKba2T95HlpJgi4b/7woCi6vOtECorwSJMhR7H7pQNOgpAg7zF24w0W2mF7a8yV o6P8CRvyHsGlzXIUGyTw4iDK64KzppKAktWDDKng1fiNF0OFBqH7/zAsqTV5qz2EqN yT3eSfDNqvNCSxoq6inOqBwAuMHB/yIm+bPNq1JFYJDMfITlfnSS7U09dbKdMXBxNe IN2N60hOzRIBYD6XPSHhJt1WdTN0422fdU+hF5xtQ9k0uKQVWUvZDV3s479id3rbBI eGclUxf3/o/v+AcBvDA6Cqj2hv/OHBpCpiFr839N3rVQPzr6xU1EBeZicTpaOmFFhd WybgUFYGOc95Q== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 615F01806E7 for ; Wed, 17 Jul 2024 18:32:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: * X-Spam-Status: No, score=1.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, FREEMAIL_REPLY,HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-lj1-f170.google.com (mail-lj1-f170.google.com [209.85.208.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 17 Jul 2024 18:32:47 +0000 (UTC) Received: by mail-lj1-f170.google.com with SMTP id 38308e7fff4ca-2eeb1ba040aso464091fa.1 for ; Wed, 17 Jul 2024 11:31:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1721241076; x=1721845876; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=kDByDKqxMBKzsYPFVsufg6saRE+OtLI/JWhohy+S1jM=; b=UuRavTPygHd9ku7Dq/mhWh+evafchOkmcty9BxNX3brZHs/B//vhbJ+3uz7/6K7JEy y1AEio4EPM6CVs0WMMq9VcwtEt60hv4BZZE2HKuhFMdeCVbG7Ce3qYO+mD/naqR5LpZ/ LDC+60HFw6l3Dv3oguN0BiQKrYGmGru8GvWMRKbfiy3MgrZW5CgtNTObZsPpTXLYJMiE k3ygc41qcikpK81zXJVa/235RdMu/443laCzhB9josHsPSVH0mAhdSCGC6AKvADB04un Y55yAf9bPhGVEoxbP2RH4RsS99ACs8teCyOccePuwpttcfjxI2uAKTkwQmhM1+I74l6r FH8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721241076; x=1721845876; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=kDByDKqxMBKzsYPFVsufg6saRE+OtLI/JWhohy+S1jM=; b=TkmFwQt6gw8hTW10cCY0yjze2/uPNPyoUuMqfaYZFBpj2Isj3W+Rm0EACeKR4WX7ws eABzpOdhlkWlwlIJE4V0OzLoHpONj6CnyvF4Q7Xn4MNfU5Wss+VKPidvLhlxLuW2YWE0 veCgL64f/TIx/FTtnpu9Nkv7rxlnJUy3QvINoVeBLI4twOHrgVmAZZ362WGnwxDggV2a wMg3/B65iQ1eC+LQIQ1YAiuZwgk+DJZI/hJ1IQG0xNCp/kVqPJHTkPhCieFK/gfOXCUm Z0XKCMPsK22G4WNC+w9zMaj5tgc8piDI08PKjhEHJ4Ki/uholsUlhs+ns8cqt6nL25WU e4pg== X-Forwarded-Encrypted: i=1; AJvYcCWk1Naaj6K/h+/2rl656s60a4CJGk4u5NR3BphghnRX9SVrJw7YYIqyOnienub9/SZJ5SX8q3qVQ17cnjHM2GESgo5RzwssbQ== X-Gm-Message-State: AOJu0Yyr90EqSiWnyw/wWzTmJX1/etQOuuBfJeiVog4lYTIu/zkyKO9/ 0o2SUqvJMsFONkKQHqY361O24iv3m4ztHHTxt9J7xd/lbylpuRLKC9kBPgTEbRSnj2n6itovjS6 5l5p6+xhQtF8nCOwYZds+OTOLzvM= X-Google-Smtp-Source: AGHT+IHpDO94C5UcCF5QHlKAZH0PJU4CSg8kLtzBwa48FAr1bfUeLHQAhAEZKlcGoyFYYH1YjGVDu0n8onQqHjIqZwE= X-Received: by 2002:a05:6512:2395:b0:52e:9619:e26a with SMTP id 2adb3069b0e04-52ee53b4c4bmr1681322e87.26.1721241075515; Wed, 17 Jul 2024 11:31:15 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <1118bbcd-a7b4-47bf-bf35-1a36ab4628e1@bastelstu.be> <45847b93-02bf-459f-bcd2-81ba35a12c24@bastelstu.be> <46bd4098-2936-4e46-98e9-fe55118325c2@bastelstu.be> <61ab36bc-b045-452a-84e0-87367d4c680e@bastelstu.be> <07e065f2-8f64-4bad-9a98-51f4eaf63ddb@app.fastmail.com> <2a0a4650-c2c5-4c6d-ad3a-25365b3391b2@bastelstu.be> In-Reply-To: Date: Wed, 17 Jul 2024 20:31:02 +0200 Message-ID: Subject: Re: [PHP-DEV] [RFC] Lazy Objects To: =?UTF-8?Q?Tim_D=C3=BCsterhus?= Cc: Rob Landers , =?UTF-8?Q?Benjamin_Au=C3=9Fenhofer?= , PHP Internals List Content-Type: multipart/alternative; boundary="000000000000e10d87061d75aabe" From: nicolas.grekas+php@gmail.com (Nicolas Grekas) --000000000000e10d87061d75aabe Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Dear all, Le mar. 16 juil. 2024 =C3=A0 17:51, Nicolas Grekas a =C3=A9crit : > Hi there, > > Le mar. 16 juil. 2024 =C3=A0 10:13, Nicolas Grekas < > nicolas.grekas+php@gmail.com> a =C3=A9crit : > >> >> >> Le lun. 15 juil. 2024 =C3=A0 21:42, Tim D=C3=BCsterhus a =C3=A9crit : >> >>> 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#a= uto-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 factor= y >>> then. >>> >>> What am I missing? >>> >> >> Finding the spot where the reset method would be useful is not easy. Her= e >> 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 fo= r >> 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 the= re > 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 > . 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 ca= n > end up in a hard to recover > "closed" state, preventing its use in long-running processes. However, th= anks > to the lazy-loading code infrastructure > , > recovering from such a state is possible. This method would be instrument= al > in achieving this capability without resorting to the current complex cod= e > 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 --000000000000e10d87061d75aabe Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Dear all,

Le=C2=A0mar. 16 juil. 2024 = =C3=A0=C2=A017:51, Nicolas Grekas <nicolas.grekas+php@gmail.com> a =C3=A9crit=C2=A0:
Hi there,

Le=C2=A0mar. 16 juil. 2024 =C3=A0=C2=A010:13, Nic= olas Grekas <nicolas.grekas+php@gmail.com> a =C3=A9crit=C2=A0:
=


Le=C2=A0lun. 15 juil. 2024 =C3=A0=C2=A021:42, Tim D=C3=BCsterh= us <tim@bastelstu.= be> a =C3=A9crit=C2=A0:
Hi

On 7/15/24 09:25, Nicolas Grekas wrote:
> Testing is actually a good domain where resetting lazy objects might o= pen
> interesting use cases.
> This reminded me about zenstruck/foundry, which leverages the
> LazyProxyTrait to provide refreshable fixture objects
> <https://s= ymfony.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 <= br> 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?


= Basically, the reset method is not needed when creating the lazy proxy. But= it's needed to refresh it when calling $object->_refresh(). The imp= lementation I just linked swaps the real object bound to the proxy for anot= her one (the line "Configuration::instance()->persistence()->ref= resh($object);" swaps by reference).


After chatting a bit with Benjamin on S= lack, I realized that the sentence "The indented use-case is for an ob= ject to manage its own laziness by calling the method in its constructor&qu= ot; was a bit restrictive and that there are more use cases for reset metho= ds.

Here is the revised part about resetAsLazyGhos= t in the RFC:

This method allows an object to = manage its own laziness by calling the method in its constructor, as demonstrated here. In such cases, the proposed lazy-obj= ect API can be used to achieve lazy initialization at the implementation de= tail level.

Another use case for this method is to achieve resettab= le services. In these scenarios, a service object already inserted into a c= omplex dependency graph can be reset to its initial state using the lazy ob= ject 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 "closed" state, preventing its= use in long-running processes. However, thanks to the lazy-lo= ading code infrastructure, recovering from such a state is possible. Th= is method would be instrumental in achieving this capability without resort= ing 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 additi= on restrictions to what can be done with lazy proxies. Namely, when the fac= tory 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 rest= riction to prevent a proxy from having an overridden __clone or __destruct = when the factory returns a parent, and explained why again.

<= /div>
This should simplify the overall behavior by preventing edge case= that wouldn't have easy answers. If those limitations prove too restri= ctive in practice (my experience tells me they should be fine), they could = be leveraged in the future.

On our side, this shou= ld close the last topics we wanted to address before opening the vote.

Please let us know if anyone has other concerns.
=

Cheers,
Nicolas
--000000000000e10d87061d75aabe--