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

Reply via email to