Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123619 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 5DFA61AD8F6 for ; Sat, 15 Jun 2024 17:10:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1718471486; bh=1hXrFcsJS/evI6Bn9WKDV61LjRI34fNng0IzPa9zwys=; h=In-Reply-To:References:Date:From:To:Subject:From; b=oBsIYacvwQp8G7BYKve2HAsVuwjnmYefUvuXCLADTbECuKs97kl674PKEZDzwAbch 08/NBp4WfkiHeq86PEs8WC0Zh4Jdfcu2YNIIZqrkBd+KHl8eVmglygJunvUqT44J/0 OK/fwkRAxwcRcPDH+P82FvEkhX2BHD7jNv70TBdvCD4DpKYeJk8LqudFUvTrp4X8Za vAnH1bKnyZZa5GqJtzbqForZjXpagIzZWhE/MbsUI/EvfZGNA1daKIW4JBYnijNTgS nTjUU7jZkjg1o+ZVdU7Cs5/morPwcarssltRp6U1TtVSkWXLOHYdJ+6ddpIuLBxYHS ldDISMwfr3Dbw== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D261D180555 for ; Sat, 15 Jun 2024 17:11:23 +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.1 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,RCVD_IN_DNSWL_LOW, 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 fhigh5-smtp.messagingengine.com (fhigh5-smtp.messagingengine.com [103.168.172.156]) (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 ; Sat, 15 Jun 2024 17:11:22 +0000 (UTC) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailfhigh.nyi.internal (Postfix) with ESMTP id 2B7B8114005F for ; Sat, 15 Jun 2024 13:10:11 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute1.internal (MEProxy); Sat, 15 Jun 2024 13:10:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc: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=1718471411; x= 1718557811; bh=+RAs7n7e/JqX1ikMU1tl3zXRig9y8SqdXy6EbRENp+w=; b=U QlEHc9mgx9SuC8SEzbShWtCDkyoppTR9FWxHOCvtyDYOHUi5SVwRAms977zEWkRa 8KkJe2En19DRLeE7xKmHiJAFVHauMnp7GBqEyuewj/4gdqirNMfRHIJpDi98KbY8 8tT04mDWjL/VtrZPLRXjRvTasXnN1s1psyI73Be5o0+r+QEdaMS5k3KRrx30jmtj i8gaiOihgx9nBcI3TXkefa6NPRsAbDQGYLv7sTyPCnbqHWiMRRxXKL9rEWUccaje wsUmBWlzN9gYdl1Fgl1j6p0YSj1/5Gfz6C9ql5RERbHwD5v6FcHE8fzb/0rnyEpn Yib6KnV9SVDBG2lWnIRPQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc: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=1718471411; x=1718557811; bh=+RAs7n7e/JqX1ikMU1tl3zXRig9y 8SqdXy6EbRENp+w=; b=CRn/qW4FZ05ZP8rxrW2DOuWKLoGaPlZ4kFPje8DiImIk G2uaCTa6HpIM3g9GgYRIBtWRlvYtNmledySD2PYhL+i8l+JazJgO084PGnUWfnKD dXY1iYPPMULrrzdkPDiWnyRF1vCxT9M/hgqxGpUGQwf2wgfYgiIzpG/OGmIzdjj/ OjswpGy+9Ui664Rv+58Dk5FUNF7FSfGi4ndM3ArB/HUeI4/yenyFlO/H0PH7uBzq Tay+M0zFEbTCRS7/UIZLhJnV7tsxMCtnSHRlzK/WNUKzlCxcadY2aPi8NXdnUMr4 ak/Tl/T55zqbRHrkUYil8x+zAW1PAS5i/+w8auGptw== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvledrfedvuddguddtlecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpefofgggkfgjfhffhffvufgtsehttdertderredtnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuggftrfgrthhtvghrnhepgeelgfekudeivddvteffueejffdthfejieevhefg ffekudevkedtvdelvddvffefnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpe hmrghilhhfrhhomheplhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtohhm X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id DFC671700093; Sat, 15 Jun 2024 13:10:10 -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: In-Reply-To: References: <1118bbcd-a7b4-47bf-bf35-1a36ab4628e1@bastelstu.be> Date: Sat, 15 Jun 2024 12:09:50 -0500 To: "php internals" Subject: Re: [PHP-DEV] [RFC] Lazy Objects Content-Type: text/plain From: larry@garfieldtech.com ("Larry Garfield") On Sat, Jun 15, 2024, at 8:28 AM, Arnaud Le Blanc wrote: > Hi Larry, > >> Under Common Behavior, you have an example of calling the constructor directly, using the reflection API, but not of binding the callable, which the text says is also available. Please include an example of that so we can evaluate how clumsy (or not) it would be. > > I've clarified that binding can be achieved with Closure::bind(). 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::setValue() > as in the Doctrine example in the "About Lazy-Loading strategies" > section I'm still missing an example with ::bind(). Actually, I tried to write a version of what I think the intent is and couldn't figure out how. :-) $init = function() use ($c) { $this->a = $c->get(ServiceA::class); $this->b = $c->get(ServiceB::class); } $service = 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 creates a new closure object, not modifying the existing one. So, how does this even work? > In practice we expect that makeInstanceLazy*() methods will not be > used on fully initialized objects, and that the flag will be set most > of the time, but as it is the API is safe by default. In the case an object does not have a destructor, it won't make a difference either way, correct? >> I find it interesting that your examples list DICs as a use case for proxies, when I would have expected that to fit ghosts better. The common pattern, I would think, would be: >> >> class Service { >> public function __construct(private ServiceA $a, private ServiceB $b) {} >> } >> >> $c = some_container(); >> >> $init = fn() => $this->__construct($c->get(ServiceA::class), $c->get(ServiceB::class)); >> >> $service = new ReflectionLazyObjectFactory(Service::class, $init); >> >> (Most likely in generated code that can dynamically sort out the container calls to inline.) >> >> Am I missing something? > > No you are right, but they must fallback to the proxy strategy when > the user provides a factory. > > E.g. this will use the ghost strategy because the DIC > instantiates/initializes the service itself: > > my_service: > class: MyClass > arguments: [@service_a, @service_b] > lazy: true > > But this will use the proxy strategy because the DIC doesn't > instantiate/initialize the service itself: > > my_service: > class: MyClass > arguments: [@service_a, @service_b] > factory: [@my_service_factory, createService] > lazy: true > > The RFC didn't make it clear enough that the example was about the > factory case specifically. Ah, got it. That makes more sense. Which makes me ask if the $initializer of a proxy should actually be called $factory? Since that's basically what it's doing, and I'm unclear what it would do with the proxy object itself that's passed in. >> ReflectionLazyObjectFactory is a terrible name. Sorry, it is. :-) Especially if it's subclassing ReflectionClass. If it were its own thing, maybe, but it's still too verbose. I know you don't want to put more 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 on 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 instance > 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 looked at the reflection implementation in, well, ever. :-) If it has to be a separate object, please don't make it extend ReflectionClass but still give it useful dynamic methods rather than static methods. Or perhaps even do something like $ghost = new ReflectionGhostInstance(SomeClass::class, $init); $proxy = new ReflectionProxyINstance(SOmeClass::class, $init); And be done with it. (I'm just spitballing here. As I said, I like the feature, I just want to ensure the ergonomics are as good as possible.) --Larry Garfield