Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:123612 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 E29C81A009C for ; Sat, 15 Jun 2024 13:28:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1718458205; bh=EV1+psowG3sU/K7P9xdhYROfx4a2p76OEc3lXrKZ8dk=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=VBiBIFV6Yqf0YrSd9YtfQvMv+uwNAbeTPEOrKFThHLH224mSzAC1I6opcDQzyzro4 BQEX8cdjNUPkQx/N3MYgBLjmjFaG4gSOw1UVhy5j06+9ssEudOq6xfE4SWZX2xqJ2e gmA8aEPvEvGxEsr38HmikwzVntk4ddJlN9sAksG8X8HV7MUIsggilhG7POJqckAsp8 KQz0CadNKdMt4epmzubhOwKfGbw3N1XuoXCy8c3mQFHqdSSjIYQ4UoDE1Z1fNAMfiV 5hApQpew1GdpvnBmUj8D9hM0zXcRxfSK/0C/qbscdDpxyd8OW8PXVsVd5CoGJxw7t3 MK4n568NOI3HA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 7EB3D18004B for ; Sat, 15 Jun 2024 13:30:04 +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, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS, 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 mail-ej1-f48.google.com (mail-ej1-f48.google.com [209.85.218.48]) (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 13:30:04 +0000 (UTC) Received: by mail-ej1-f48.google.com with SMTP id a640c23a62f3a-a6269885572so710747166b.1 for ; Sat, 15 Jun 2024 06:28:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1718458132; x=1719062932; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=wPnjPOWQJHo+30XZVd/O4hg3cl6QgYAT7v7Qjpjv0Ao=; b=CplGYvSyZCpAq3Upfj9kgB6F0xiD5kX2wefER7/L9hoBgkSqZzxTI+GExXA4FUUbdt sCQvTSVjVsEsq9Kd5RZZIVwui7g93vdW3EiYZtGqmXZNCAlrQ77Uy/6oHmQvLc0Twqrv J9Q1VlLMbT1nNB6JXHVlW5FbirPfbWmOn9LdLtwq+V7kVBWyZib7CTKZtS/Evrw5A7YJ KjxTJl+rouPuV9LLIFoiHNHJPxTAORZwCsbFUnYXXdYZJgnxsKyEHcgyrDT6O0P5d+Rz 8CBqYYIMCMUxM12crmt6yh0xDAGNgRfBcTRQ7H/36CrtjhmY4gtprcfkchGLZOabcDgv aaKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1718458132; x=1719062932; h=content-transfer-encoding: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=wPnjPOWQJHo+30XZVd/O4hg3cl6QgYAT7v7Qjpjv0Ao=; b=KKzhWx1Kghw2PAZfcfWpw17O/ONgbAKXsm3XVNf5ShLHrEUECIuSfhIsBCcqMJgTBB UxGNIaBtJSP2S6A4r7RKaPMDfQQakKCWjwqshrbVrzksKGtxI77QSIRh9PEQ7bZupzLI Xy9ZlkPiX2uvHmxF86bsxAtXlPkD2e6on+rGQemninAE6DrO+9aQsA0Ahxtx8Klnoatc KYUfljjuvqE0qzDI/Vp4bhLKIQI6XgnbKKdR3wjrbeHiaBKx2eHBJ4UQPeqiCyb3+OX3 sOeMACg2jLgc3KczyjqVBEpDNCAQETbzOqWG7Vu6z1UBFjFsJnyEopxer+usdSOOfTew STUA== X-Gm-Message-State: AOJu0YxRUWd2KY/ZermAPLBsuP9OPyA3j02caiz3vO9vtzvDQFLegyod +KGMF9FRQ+nDf6Ghj1rax3H22nQCfhHtUX/duWg9+IySsgL2/KsHjPf5QQXRI4wAnrTu5jxPdkn GxHGe4VcfzdgcZXylNdbZo9Drxf0AeQIZ X-Google-Smtp-Source: AGHT+IFNgcPX1RQ0T8inl17nHqDqt8YmsRbzG80kZhN3EMILFlBNl7pLl9L2ZnXR2H199VjcfFpnifOH9YE9cFfAliI= X-Received: by 2002:a17:906:d7a2:b0:a6f:1c58:754a with SMTP id a640c23a62f3a-a6f5245cd05mr514591366b.24.1718458132044; Sat, 15 Jun 2024 06:28:52 -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> In-Reply-To: Date: Sat, 15 Jun 2024 15:28:40 +0200 Message-ID: Subject: Re: [PHP-DEV] [RFC] Lazy Objects To: Larry Garfield Cc: php internals Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: arnaud.lb@gmail.com (Arnaud Le Blanc) Hi Larry, On Fri, Jun 14, 2024 at 10:18=E2=80=AFPM Larry Garfield wrote: > > The actual instance is allowed to escape the proxy and to create direct= references to itself. > > How? Is this a "return $this" type of situation? This could use more fl= eshing out and examples. "return $this" will return the proxy object, but it is possible to create references to the actual instance during initialization, either directly in the initializer function, or in methods called by the initializer. The "About Proxies" section discusses this a bit. I've added an example. > The terms "virtual" and "proxy" seem to be used interchangeably in differ= ent places, including in the API. Please just use one, and purge the other= . It's confusing as is. :-) (I'd favor "proxy", as it seems more accurate= to what is happening.) Agreed > Under Common Behavior, you have an example of calling the constructor dir= ectly, 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 constru= ctor - Those that initialize everything with ReflectionProperty::setValue() as in the Doctrine example in the "About Lazy-Loading strategies" section > > After calling newLazyGhostInstance(), the behavior of the object is the= same as an object created by newLazyGhostInstance(). > > I think the first is supposed be a make* call? Thank you! > > When making an existing object lazy, the makeInstanceLazy*() methods ca= ll the destructor unless the SKIP_DESTRUCTOR flag is given. > > I don't quite get why this is. Admittedly destructors are rarely used, b= ut why does it need to call the destructor? The rationale is that unless specified otherwise, we must assume that the constructor has been called on the object. Therefore we must call the destructor before resetting the object's state entirely. See also the Mutex example given by Tim. I've added the rationale and an example. 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. > I find it interesting that your examples list DICs as a use case for prox= ies, when I would have expected that to fit ghosts better. The common patt= ern, I would think, would be: > > class Service { > public function __construct(private ServiceA $a, private ServiceB $b)= {} > } > > $c =3D some_container(); > > $init =3D fn() =3D> $this->__construct($c->get(ServiceA::class), $c->get(= ServiceB::class)); > > $service =3D new ReflectionLazyObjectFactory(Service::class, $init); > > (Most likely in generated code that can dynamically sort out the containe= r 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. > ReflectionLazyObjectFactory is a terrible name. Sorry, it is. :-) Espec= ially 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 "du= mping ground" fo ReflectionClass, but honestly, that feels more ergonomic t= o 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(), ini= tialized(), etc. also feel like they make more sense as methods on Reflecti= onObject, 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