Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123636 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 9275F1A009C for ; Sun, 16 Jun 2024 14:36:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1718548638; bh=qL2K9StdYAAUkyaEpIc0/cvpOrzlVZDuNtpZ1LpgSGU=; h=In-Reply-To:References:Date:From:To:Subject:From; b=MKsq7WMy3W6hTRo9mqZbAKp1O69UXoXFx1WJK1FWlARa28LY0oUQDFD4NYYre1WV0 jjizWAyPcuXGLyEwu3R/g+FYYlk8SsZ4FQPqXGpHSvMw1dQAwiJUMlrnI+BMh7XuSi nuYiVahIGKBwCi8dg5I3bXXYRYIpyxTo8G2Er6UZAcjJMLdD6YQa0je02RgBwLUP9u A9M4oD/JMy80fUfbv5LVDTAEdAmoJOqp0GTDhpyMEzjJ/9abHb/ghrOWIedxAOuUj+ qZTAPSS0Gcp+3I9fo+XkYd3Ddkq9R/QZwPRw4FwAN81XLVPk4ODht3LWY/6SqoVk4T Lz8FjmGK3PBpw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id B34E1180590 for ; Sun, 16 Jun 2024 14:37:13 +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_MISSING,SPF_HELO_PASS, SPF_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from fhigh2-smtp.messagingengine.com (fhigh2-smtp.messagingengine.com [103.168.172.153]) (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 ; Sun, 16 Jun 2024 14:37:13 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfhigh.nyi.internal (Postfix) with ESMTP id 7E8F81140071 for ; Sun, 16 Jun 2024 10:36:01 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute1.internal (MEProxy); Sun, 16 Jun 2024 10:36:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to; s=fm1; t=1718548561; x=1718634961; bh=0odG95uKV+XOWkPZc4K5S qc8lqX7jJ77srICyeOBhkI=; b=rTDHbgqWgKbxMmQO/RLHQKq1d9ACYRduN4q+s Wo0SFCLcMQ7HGZYVnQrMG92lvoGLq16H1/NIPb0VIhvaI29J9nEj/ovhEGhFx3fz BIlumL7N22nt7djfDRePh3J/VOHddWuKvWd9Wlfg1y6OIm9iqZA4jtYdT/1QLyZa Vvt15eOnMEn6pys5/8xoYTDytJOYP0oR7sbqGdVDEqW+nlZ0MQ3GqOoKupZPfoUk Zn7ytPWvXrLJNbXkCVQbBYQJzVEHTMEqU6BUHgFyHKD7psSFCxBgF2n2Bt5bMXMq hh7D5mZeY6KBJda5t5yMHmlE3ckcym1+PjEeT3aCHjVrYI7Ag== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1718548561; x= 1718634961; bh=0odG95uKV+XOWkPZc4K5Sqc8lqX7jJ77srICyeOBhkI=; b=F ygGvvBB/8xjg8Cl7sSP1Pyz5ZjNk/PPqobkPzrJuYaYlAdI9FJa3ARZv8HSyfhDe DafBYawHr4Q8TVAKQngduRNIz6gY9i0gD2KyCMd//+PUBrjekC05K143BDNmriGB 0N3G58rnhXkiztJGteR4YzWCJ8bpPMl5Hf9OK542rAjlnDYwxma1Ta1SzPbgYJyD x0fLeXzf0+LL2hl9ZawY4PjJPG/HzSKH7Mnq4qd2K+KI0nPPOoX6s0m3QRtzZgB3 ma5dfl4GJsBWGfjH0/au/W5X6+GRIyx0Qe+Fier1iYvjRFiuD1Io0Gvjr1A1kRjq OveIWPNp3XRUtvVWu0ZnA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrfedvfedgjeekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgfgsehtqhertderreejnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuggftrfgrthhtvghrnhepffffffejffdugfegvedviedttedvgfejffefffej leefjeetveehgefhhfdvgfelnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpe hmrghilhhfrhhomheplhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhm X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 0AFFA1700093; Sun, 16 Jun 2024 10:36:00 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.11.0-alpha0-515-g87b2bad5a-fm-20240604.001-g87b2bad5 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 Message-ID: <71981e0f-2293-45cb-b3e4-0b115a52220b@app.fastmail.com> In-Reply-To: References: <1118bbcd-a7b4-47bf-bf35-1a36ab4628e1@bastelstu.be> Date: Sun, 16 Jun 2024 09:35:40 -0500 To: "php internals" Subject: Re: [PHP-DEV] [RFC] Lazy Objects Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable From: larry@garfieldtech.com ("Larry Garfield") On Sun, Jun 16, 2024, at 8:46 AM, Arnaud Le Blanc wrote: > On Sat, Jun 15, 2024 at 7:13=E2=80=AFPM Larry Garfield wrote: >> > In practice I expect there will be two kinds of ghost initializers: >> > - Those that just call one public method of the object, such as the= constructor >> > - Those that initialize everything with ReflectionProperty::setValu= e() >> > as in the Doctrine example in the "About Lazy-Loading strategies" >> > section >> I'm still missing an example with ::bind(). Actually, I tried to wri= te a version of what I think the intent is and couldn't figure out how. = :-) >> >> $init =3D function() use ($c) { >> $this->a =3D $c->get(ServiceA::class); >> $this->b =3D $c->get(ServiceB::class); >> } >> >> $service =3D new ReflectionLazyObjectFactory(Service::class, $init); >> >> // We need to bind $init to $service now, but we can't because $init = is already registered as the initializer for $service, and binding creat= es a new closure object, not modifying the existing one. So, how does t= his even work? > > Oh I see. Yes you will not be able to bind $this in a simple way here, > but you could bind the scope. This modified example will work: > > ``` > $init =3D function($object) use ($c) { > $object->a =3D $c->get(ServiceA::class); > $object->b =3D $c->get(ServiceB::class); > } > $service =3D new ReflectionLazyObjectFactory(Service::class, > $init->bindTo(null, Service::class)); > ``` > > If you really want to bind $this you could achieve it in a more convol= uted way: > > ``` > $init =3D function($object) use ($c) { > (function () use ($c) { > $this->a =3D $c->get(ServiceA::class); > $this->b =3D $c->get(ServiceB::class); > })->bindTo($object)(); > } > $service =3D new ReflectionLazyObjectFactory(Service::class, $init); > ``` > > This is inconvenient, but the need or use-case is not clear to me. > Could you describe some use-cases where you would hand-write > initializers like this? Do you feel that the proposal should provide > an easier way to change $this and/or the scope? Primarily I was just reacting to this line: > However, for more complex use-cases where the initializer wishes to ac= cess non-public properties, it is required to bind the initializer funct= ion to the right scope (with Closure::bind()), or to access properties w= ith ReflectionProperty.=20 And asking "OK, um, how?" Because what I was coming up with didn't make= any sense. :-) =20 It's debatable if the use case of wanting to assign to private propertie= s in the initializer without using Reflection is common enough to warran= t more. I'm not sure at this point. If we wanted to, I could see an ex= tra flag that would tell the system to bind the closure to the object be= fore calling it. I don't know how common a need that will be, though, s= o I won't insist it be included. But I would like to see that line clar= ified with one of the above examples, because as is, I would expect to b= e able to bind to the object as I was trying to do and it (obviously) di= dn't work. >> and I'm unclear what it would do with the proxy object itself that's = passed in. > > Passing the factory itself as argument could be used to make decisions > based on the value of some initialized field, or on the class of the > object, or on its identity. I think Nicolas had a real use-case where > he detects clones based on the identity of the object: > > ``` > $init =3D function ($object) use (&$originalObject) { > if ($object !=3D=3D $originalObject) { > // we are initializing a clone > } > }; > $originalObject =3D $reflector->newProxyInstance($init); > ``` > > This was on ghosts, but I think it's also a valid use-case example for= proxies. Hm, interesting. Please include this sort of example in the RFC, so we = know what the use is (and when it won't matter, which seems like it woul= d be the more common case). >> >> ReflectionLazyObjectFactory is a terrible name. Sorry, it is. :-)= Especially if it's subclassing ReflectionClass. If it were its own th= ing, maybe, but it's still too verbose. I know you don't want to put mo= re on the "dumping ground" fo ReflectionClass, but honestly, that feels = more ergonomic to me. That way the following are all siblings: >> >> >> >> newInstance(...$args) >> >> newInstanceWithoutConstructor(...$args) >> >> newGhostInstance($init) >> >> newProxyInstance($init) >> >> >> >> That feels a lot more sensible and ergonomic to me. isInitialized= (), initialized(), etc. also feel like they make more sense as methods o= n ReflectionObject, not as static methods on a random new class. >> > >> > Thank you for the suggestion. We will check if this fits the >> > use-cases. Moving some methods on ReflectionObject may have negative >> > performance implications as it requires creating a dedicated instan= ce >> > for each object. Some use-cases rely on caching the reflectors for >> > performance. >> > >> > Best Regards, >> > Arnaud >> >> I'm not clear why there's a performance difference, but I haven't loo= ked at the reflection implementation in, well, ever. :-) > > What I meant is that creating an instance (not necessarily of > ReflectionObject, but of any class) is more expensive than just doing > nothing. The first two loops below would be fine, but the last one > would be slower. This can make an important difference in a hot path. > > ``` > foreach ($objects as $object) { > ReflectionLazyObject::isInitialized($object); > } > > $reflector =3D new ReflectionClass(SomeClass::class); > foreach ($objects as $object) { > $reflector->isInitialized($object); > } > > foreach ($objects as $object) { > $reflector =3D new ReflectionObject($object); > $reflector->isInitialized($object); > } > ``` Ah, now I see what you mean. Interesting. Including that reasoning in = the RFC would be good. Though, I don't know how often I'd be calling is= Initialized() on a larger set of objects, hot path or no. =20 --Larry Garfield