On Wed, Jun 5, 2024 at 6:58 PM Nicolas Grekas <nicolas.grekas+...@gmail.com> wrote: > > Hi Tim, > > Thanks for the detailed feedback. Arnaud already answered most of your > questions, here is the remaining one: > >> On 6/4/24 14:28, Nicolas Grekas wrote: >> > Please find all the details here: >> > https://wiki.php.net/rfc/lazy-objects >> > >> > We look forward to your thoughts and feedback. >> >> I've gave the RFC three or four passes and I'm not quite sure if I >> follow everything, here's a list of some questions / remarks that came >> to mind, roughly ordered by the order of things appearing in the RFC. >> >> - "been tested successfully on the Doctrine and on the Symfony projects" >> >> Is there a PoC patch showcasing how the code would change / be >> simplified for those pre-existing codebases? > > > Yes! > See https://github.com/nicolas-grekas/symfony/pull/44 for Symfony. All the > complex code is gone \o/ > And if anyone is wondering: No, we're not moving this complexity into the > engine. As Arnaud wrote somewhere: Implementation in core is simple compared > to userland as we are at the right level of abstraction. No code gen, no edge > cases with relative type hints, visibility, readonly, hooks, etc. We get more > consistent and transparent behavior as well compared to userland impl. > > For Doctrine, the URL is > https://github.com/nicolas-grekas/doctrine-orm/pull/6 for now, with the most > important line being the removal of the symfony/var-exporter dependency. > > After yours and Valentin's feedback, we're considering an updated API that > would provide the same capabilities but that might be more consensual. > > The RFC isn't updated but below is what we have in our drafts. Let me know > what you think already if you want (otherwise, let us work on the updated > implementation/RFC and we'll let you know about them ASAP). > > Nicolas > PS: I understand that the concepts in the RFC might be difficult to grasp. > They were certainly challenging for me to summarize. I would happily accept > any help to improve the wording if anyone is willing. > > > class ReflectionLazyClass extends ReflectionClass > { > public int const SKIP_INITIALIZATION_ON_SERIALIZE = 1; > public int const SKIP_DESTRUCTOR = 2; > > public function __construct(object|string $objectOrClass); > > public function newLazyGhostInstance(callable $initializer, int $options = > 0): object; > public function newLazyProxyInstance(callable $initializer, int $options = > 0): object; > > public function makeInstanceLazyGhost(object $object, callable $initializer, > int $options = 0): void; > public function makeInstanceLazyProxy(object $object, callable $initializer, > int $options = 0): void; > public static function isInitialized(object $instance): bool; > /** > * Initializes a lazy object (no-op if the object is already initialized.) > * > * The backing object is returned, which can be another instance than the lazy > object when the virtual strategy is used. > */ > public function initialize(object $object, bool $skipInitializer = false): > object; > /** > * Marks a property as *not* triggering initialization when being accessed. > * > * This method is useful to bypass initialization when setting a property. > */ > public function skipInitializerForProperty(object $object, string $name, > string $class = null): void; > /** > * Sets a property *without* triggering initialization while skipping hooks if > any. > */ > public function setRawPropertyValue(object $object, string $name, mixed > $value, string $class = null): void; > }
For virtual proxies, it would be nice if the instance returned didn't have to be the same type or child type. For example, in Durable PHP, I allow accessing remote entities via a Spying Proxy: $ctx->signal($id, fn(MyEntity $obj) => $obj->doSomething($x)); In this example, ->signal() generates/loads the proxy which implements MyEntity with code that captures the value of $x to be forwarded to a remote instance. It then calls the passed closure and captures the method + arguments passed. Most of the complexity is generating the objects themselves to implement the methods. It would be much simpler to implement magic methods that can intercept the method calls and not worry about generating an entire class every time a dev wants to use this functionality. In my case, none of the complexity actually goes away since I still need to generate concrete types of the correct type. That being said, I don't exactly have millions of users so if I still need to manually create this, I will. I just thought I'd toss out the idea of not needing an object of the correct type, just one that can handle the expected behavior. Robert Landers Software Engineer Utrecht NL