On Mon, Apr 17, 2023, at 7:43 AM, Alexandru Pătrănescu wrote: > On Mon, Apr 17, 2023, 07:32 Máté Kocsis <kocsismat...@gmail.com> wrote: > >> finally I managed to create a working implementation for this feature which >> would make it possible to properly modify readonly properties >> while simplifying how we write "wither" methods: >> https://wiki.php.net/rfc/clone_with
A solid RFC, thanks! I agree with the discussion of Nicolas's alternative, which has its merits but also some possible limitations. My only major concern myself is the potential confusion between when to use : and when to use =>. Using the => version only for dynamic keys feels very clunky. In fact, I think the RFC is inconsistent on this front: $object = clone $object with {"foo" => 1}; // the property name is a literal $object = clone $object with {strtolower("FO") . "o" => 1}; // the property name is an expression $object = clone $object with {PROPERTY_NAME => 1}; // the property name is a named constant I would expect the first one to be a colon, not fat-arrow. Is that a typo? Is there a technical reason why they can't just all use a colon? That would extend more nicely to supporting dynamic keys in the future for named arguments. > Hey Máté, > > How about just allowing a block of code after the clone statement that > would execute it in the same context as the clone context, allowing to > modify once readonly variables. > Allows better flexibility compared with clone with syntax or clone metho: > > public function withStatus($code, $reasonPhrase = ''): Response > { > return clone $this { > $this->statusCode = $code; > > $this->reasonPhrase = $reasonPhrase; > > }; This is an interesting alternative. I don't think $this is that confusing, actually. Inside __clone(), $this always refers to the new object. This proposal would essentially be providing an additional __clone block that runs in the same context, viz, $this always refers to the new object. I'm not sure if you need the original object separately at all, in fact; if you want to look up a value from the original object... you already have it on the new object in the same location, because it's a clone. So: public function withStatus($code, $reasonPhrase = ''): Response { return clone $this { $this->statusCode = $code; $this->reasonPhrase = "Old: $this->reasonPhrase, New: $reasonPhrase"; } }; $this->reasonPhrase in the string refers to the cloned object, where that value is by definition identical to the original object. It's evaluated, the string is computed, and then the clone's reasonPhrase property is updated. The catch here is 2 fold: 1. This would essentially imply auto-capture. While I am quite OK with that, a fair number of people are not. But adding a use() block to that syntax just makes it very clunky for the obvious common case; which is basically the above, so it just forces you to repeat each variable name a third time. I would probably vote against something that forced more redundant use() statements. 2. The scope permissioning becomes weirder. The current RFC syntax is very predictable: properties get assigned from the context at which the clone statement lives, and if there are private/protected restrictions those are self-evident. With the more closure-like approach, it "feels" like you're providing an anon function that will get bound to the new object and then executed... which would then always run with private scope and be able to modify values you probably didn't want to be publicly modifiable. While we could potentially implement it such that the scope rules are still enforced, that may not be as obvious why you can/can't mess with a particular variable. I'm open to this alternative though if Mate is; it has potential, but we'd have to sort out the above. --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php