Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:124427 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 A6FC11A00B7 for ; Mon, 15 Jul 2024 10:00:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1721037697; bh=sSk7KkjMPQSmhjtewnWMPgbIqWmh9y5c1W7kamjajJ0=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=Qca1oEWVjJIkJu1NEWvlQlnrHIkmCd9nm0FPYbRSE9CJHZyGiIDTDw7jrc/hVKLMw tHOTUAbLmK3FxqHzmWYQb1o3R8uKQiotAmcisPkFuHXvnC/pAH8FP/zFNZJT6Wa2/a HVSCKMUymsToGxTE4Xbf0kL1IaiQeF3JQDhL8k+ACvKRPzT7wdek/27STz+9BgLmDx FXXU+WWplQSuyU7E8m/q9H9/IqDp6KrCL+F840rOTbM4PPUDh90pTwHPfsjwDWR9n9 IGSky80e8p0wW8gfucNdUklV6bIgofiJQHct5FEYx+1ZS7jkEX1BmWQwy1iyY39eNw ogFZln1OgmJHw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 04B501805AE for ; Mon, 15 Jul 2024 10:01:36 +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=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, 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-f181.google.com (mail-lj1-f181.google.com [209.85.208.181]) (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 ; Mon, 15 Jul 2024 10:01:35 +0000 (UTC) Received: by mail-lj1-f181.google.com with SMTP id 38308e7fff4ca-2eeb2d60efbso48033781fa.1 for ; Mon, 15 Jul 2024 03:00:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1721037605; x=1721642405; 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=vMC5nbnketWavkgSYDZBO7U7T2/YRuue/A4G6oh0JOU=; b=hx3Oe11BRrEkjSd8c/bFeg4iDees7SQcwelfiuCW2XmE9KD+EMYLOwd2Vnoryc8JK6 pbrjVcOyv0xUfoKom3PCIsxdC3kxWoqvwtOrrrAdAeipPcjLOpnHCOLo1neKzdsS+efI uVLCmTgy0YDQmF+iyFS/bOlHdylSvULQPPPaSf2kACOH1ox93xt/5daDR6tZY2TjxM3e SNl1I3swz+A1RdU5yzR6W6i5wnYUux/AaQjuYZ728sE2jcP+SuEwm/gy1NCf5U4cvmSp tcpUpxeW9/GaaVCpsvfHPSQnhBSDHP0MeUChcBkfynSNwgKBkY1GQ/5PyaSqIFOs9iMD LvyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1721037605; x=1721642405; 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=vMC5nbnketWavkgSYDZBO7U7T2/YRuue/A4G6oh0JOU=; b=AweDtUxAd+vj021pDYj6Luw5FWnds7Sq4dtCoo4NM4YneZsTn8fXqGa5PcmpNLjPFI mie9os5FXsKpvgyasRJLXsLXcBCxC8zVGSqLaFGsbdJ26rgkCKcRKM/eE3JliX6c1j1s jeZLS2kpL3c5zxmtT+mNHdxDKX/l4nX+DrjB3atjKLlVoVtKl5Z3bxUWzgNuku2HLn5m j3z2CuiP+ZK6ILdIBJBbQPRzc2wImEq/hTHZRzbs19SOtNl0AMpvORMhjUVPGHum6c6v Y3tO4IQaNIfMMn244gUPO8N/vrR37AydLV7D7dAzHhRA8xVU3ODGYHyHvvwZ9S6gq658 rwQA== X-Forwarded-Encrypted: i=1; AJvYcCURV1O9dG5Y7vspyY1Yl1xaT89iDX9q1c9XExggINHSZTULkxVNhKJe9g8XiT2pye+qe1aHLkYtD5y9u3uKtNkcnW2Zzn3mPA== X-Gm-Message-State: AOJu0YwTiDtX1sx7yydFH9m/kGj5YwCbxhQ2A12bwlX6/c9Vz8N0ERey nDTuinQrQgVJelLy5sQVRrbbeIeGJNHBBb7bO2agb+TiJQVC3cUxEf9uIxG8avEIhi+74aihpHb sPJQMvn1Heshb4wI+GQgvFbA982c= X-Google-Smtp-Source: AGHT+IEZNhiIE4cKqhH8H7GEr3+pJ8906ylvLJ12UYMSIalLjjoqDEnMPurztIdHWuT1JSKitpY7FeVeEk8SlApm4xs= X-Received: by 2002:a2e:8797:0:b0:2ee:854f:45be with SMTP id 38308e7fff4ca-2eeb30e528dmr121515721fa.12.1721037604727; Mon, 15 Jul 2024 03:00:04 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net 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> In-Reply-To: Date: Mon, 15 Jul 2024 11:59:52 +0200 Message-ID: Subject: Re: [PHP-DEV] [RFC] Lazy Objects To: =?UTF-8?Q?Benjamin_Au=C3=9Fenhofer?= Cc: =?UTF-8?Q?Tim_D=C3=BCsterhus?= , PHP Internals List Content-Type: multipart/alternative; boundary="000000000000133177061d464bcf" From: nicolas.grekas+php@gmail.com (Nicolas Grekas) --000000000000133177061d464bcf Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Le ven. 12 juil. 2024 =C3=A0 01:40, Benjamin Au=C3=9Fenhofer a =C3=A9crit : > > > Am 11.07.2024, 20:31:44 schrieb Tim D=C3=BCsterhus : > >> Hi >> >> On 7/11/24 10:32, Nicolas Grekas wrote: >> >> > Many things are already possible in userland. That does not always mea= n >> >> > that the cost-benefit ratio is appropriate for inclusion in core. I ge= t >> >> > behind the two examples in the =E2=80=9CAbout Lazy-Loading Strategies= =E2=80=9D section, >> >> > but I'm afraid I still can't wrap my head why I would want an object >> >> > that makes itself lazy in its own constructor: I have not yet seen a >> >> > real-world example. >> >> > >> >> >> Keeping this capability for userland is not an option for me as it would >> >> mostly defeat my goal, which is to get rid of any userland code on this >> >> topic (and is achieved by the RFC). >> >> >> Here is a real-world example: >> >> >> https://github.com/doctrine/DoctrineBundle/blob/2.12.x/src/Repository/La= zyServiceEntityRepository.php >> >> >> This class currently uses a poor-man's implementation of lazy objects an= d >> >> would greatly benefit from resetAsLazyGhost(). >> >> >> >> Sorry, I was probably a little unclear with my question. I was not >> specifically asking if anyone did that, because I am fairly sure that >> everything possible has been done before. >> >> I was interested in learning why I would want to promote a >> "LazyServiceEntityRepository" instead of the user of my library just >> making the "ServiceEntityRepository" lazy themselves. >> >> I understand that historically making the "ServiceEntityRepository" lazy >> yourself would have been very complicated, but the new RFC makes this >> super easy. >> >> So based on my understanding the "LazyServiceEntityRepository" >> (c|sh)ould be deprecated with the reason that PHP 8.4 provides all the >> necessary tools to do it yourself, no? That would also match your goal >> of getting rid of userland code on this topic. >> >> To me this is what the language evolution should do: Enable users to do >> things that previously needed to be provided by userland libraries, >> because they were complicated and fragile, not enabling userland >> libraries to simplify things that they should not need to provide in the >> first place because the language already provides it. >> > > I agree with Tim here, the Doctrine ORM EntityRepository plus Symfony > Service Entity Repository extension are not a necessary real world case > that would require this RFC to include a way for classes to make > themselves lazy. > > I took the liberty at rewriting the code of DefaultRepositoryFactory > (Doctrine code itself) and ContainerRepositoryFactory in a way to make th= e > repositories lazy without needing resetAsLazy, just > $reflector->createLazyProxy. In case of the second the > LazyServiceEntityRepository class could be deleted. > > https://gist.github.com/beberlei/80d7a3219b6a2a392956af18e613f86a > Thanks for the example. Here is the quick diff: Before: return $this->managedRepositories[$repositoryHash] =3D new $repositoryClassName($entityManager, $metadata); After: $reflector =3D new ReflectionClass($repositoryClassName); return $this->managedRepositories[$repositoryHash] =3D $reflector->newLazyProxy(static fn () =3D> new $repositoryClassName($entityManager, $metadata); But in the case of repositories registered as services, this code path won't be reached for the class we're talking about (we'll take the "$container->has()" code path). Yet we need to account for the history of such a piece of code: the service repository class I shared uses laziness internally because this was the most effective way to handle circular references seamlessly without breaking any of the currently working consumer apps. With refactoring, we can fix all design issues in all softwares. Yet that's too theoretical and this is missing the point IMHO. What we want to provide is a complete coverage of the lazy object domain. Simplifying too much can lead to an incomplete solution that'd be too restrictive. Please let me know if this is not how it works or can work or if my > reasoning is flawed. > > Unless you have no way of getting to the =E2=80=9Enew $object=E2=80=9C in= the code, there > is always a way to just use newLazy*. And when a library does not expose > new $object to you to override, then that is an architectural choice (and > maybe flaw that you have to accept). > I still think not having the reset* methods would greatly simplify this RFC > and would allow to force more constraints, have less footguns. > > For example we could simplify the API of newLazyProxy to not receive a > $factory that can arbitrarily create and get objects from somewhere, but > also initializer and always force the lazy object to be an instance creat= ed > by newInstanceWithoutConstructor. > > You said in a previous mail about reset*() > > From a technical pov, this is just a different flavor of the same code >> infrastructure, so this is pretty aligned with the rest of the proposed >> API. >> > > We are not specifically considering the technical POV, but even more > importantly the user facing API. And this just adds to the surface of the > API a lot of things that are pushing only a 1-5% edge case. > I share this angle: figuring out the minimal API to cover the domain. Yet I showed reset methods proved useful already (see also my example about refreshable fixtures) - not only as "just tools", but more importantly from a theoretical aspect as a useful API to cover all situations that userland will encounter (and does already). If we don't have them, I know I will have to maintain a library that already provides this resetting capability because there are valid use cases for them. That'd be a failure to address the needs of userland on the topic to me. Cheers, Nicolas --000000000000133177061d464bcf Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
Le=C2=A0ven. 12 juil. 2024 =C3=A0=C2= =A001:40, Benjamin Au=C3=9Fenhofer <kontakt@beberlei.de> a =C3=A9crit=C2=A0:


Am 11.07.2024, 20:31:44 schrieb T= im D=C3=BCsterhus <tim@bastelstu.be>:
=20
Hi

On 7/11/24 10:32, Nicolas Grekas wrote:
> Many things are already possible in userland. That does not = always mean
> that the cost-be= nefit ratio is appropriate for inclusion in core. I get
> behind the two examples in the =E2=80=9CAbout L= azy-Loading Strategies=E2=80=9D section,
> but I'm afraid I still can't wrap my head why I woul= d want an object
> that makes = itself lazy in its own constructor: I have not yet seen a
<= blockquote type=3D"cite">> real-world example.
>

Keeping this capability for userland is n= ot an option for me as it would
= mostly defeat my goal, which is to get rid of any userland code on this
=
topic (and is achieved by the RFC).=

Here is a real-world example:
https:/= /github.com/doctrine/DoctrineBundle/blob/2.12.x/src/Repository/LazyServiceE= ntityRepository.php

This class currently uses a poor-man= 9;s implementation of lazy objects and
would greatly benefit from resetAsLazyGhost().


Sorry, I was probably a little u= nclear with my question. I was not
specifically asking if anyone did th= at, because I am fairly sure that
everything possible has been done bef= ore.

I was interested in learning why I would want to promote a
= "LazyServiceEntityRepository" instead of the user of my library j= ust
making the "ServiceEntityRepository" lazy themselves.
=
I understand that historically making the "ServiceEntityRepository= " lazy
yourself would have been very complicated, but the new RFC = makes this
super easy.

So based on my understanding the "La= zyServiceEntityRepository"
(c|sh)ould be deprecated with the reaso= n that PHP 8.4 provides all the
necessary tools to do it yourself, no? = That would also match your goal
of getting rid of userland code on this= topic.

To me this is what the language evolution should do: Enable = users to do
things that previously needed to be provided by userland li= braries,
because they were complicated and fragile, not enabling userla= nd
libraries to simplify things that they should not need to provide in= the
first place because the language already provides it.

I agree with Tim here,= the Doctrine ORM EntityRepository plus Symfony Service Entity Repository e= xtension are not a necessary real world case that would require this RFC = =C2=A0to include a way for classes to make themselves lazy.

I took the liberty at rewriting the code of DefaultRepositoryFactory (Do= ctrine code itself) and ContainerRepositoryFactory in a way to make the rep= ositories lazy without needing resetAsLazy, just $reflector->createLazyP= roxy. In case of the second the LazyServiceEntityRepository class could be = deleted.


Thanks for the example. Here is the quick diff:

Before:
return $this->managedRepositories[$rep= ositoryHash] =3D new $repositoryClassName($entityManager, $metadata);
=

After:
$reflector =3D new ReflectionClass($repositoryClassName);<= br>return $this->managedRepositories[$repositoryHash] =3D $reflector->= ;newLazyProxy(static fn () =3D> new $repositoryClassName($entityManager,= $metadata);

But in th= e case of repositories registered as services, this code path won't be = reached for the class we're talking about (we'll take the "$co= ntainer->has()" code path).

Yet we need to= account for the history of such a piece of code: the service repository cl= ass I shared uses laziness internally because this was the most effective w= ay to handle circular references seamlessly without breaking any of the cur= rently working consumer apps.

With refactoring= , we can fix all design issues in all softwares. Yet that's too theoret= ical and this is missing the point IMHO. What we want to provide is a compl= ete coverage of the lazy object domain. Simplifying too much can lead to an= incomplete solution that'd be too restrictive.


Please let me know if this is not how it works or can work or if my re= asoning is flawed.

Unless you have no way of getting to t= he =E2=80=9Enew $object=E2=80=9C in the code, there is always a way to just= use newLazy*. And when a library does not expose new $object to you to ove= rride, then that is an architectural choice (and maybe flaw that you have t= o accept).
I still think not ha= ving the reset* methods would greatly simplify this RFC and would allow to = force more constraints, have less footguns.=C2=A0

For exa= mple we could simplify the API of newLazyProxy to not receive a $factory th= at can arbitrarily create and get objects from somewhere, but also initiali= zer and always force the lazy object to be an instance created by newInstan= ceWithoutConstructor.

You said in a previous mail about r= eset*()

From a technical p= ov, this is just=C2=A0=C2= =A0a different flavor of t= he same code infrastructure, so this is pretty=C2=A0=C2=A0aligned with the rest of the proposed API.
<= div>
We are not specifically considering the technical POV, but ev= en more importantly the user facing API. And this just adds to the surface = of the API a lot of things that are pushing only a 1-5% edge case.

I share this angle: figuring out the minimal = API to cover the domain.

Yet I showed reset method= s proved useful already (see also my example about refreshable fixtures) - = not only as "just tools", but more importantly from a theoretical= aspect as a useful API to cover all situations that userland will encounte= r (and does already). If we don't have them, I know I will have to main= tain a library that already provides this resetting capability because ther= e are valid use cases for them. That'd be a failure to address the need= s of userland on the topic to me.


Ch= eers,
Nicolas
--000000000000133177061d464bcf--