Le lun. 19 mai 2025 à 16:30, Andreas Hennings <andr...@dqxtech.net> a
écrit :

> On Fri, 16 May 2025 at 21:59, Nicolas Grekas
> <nicolas.grekas+...@gmail.com> wrote:
> >
> >
> >
> > Le jeu. 15 mai 2025 à 16:06, Larry Garfield <la...@garfieldtech.com> a
> écrit :
> >>
> >> On Thu, May 15, 2025, at 1:22 AM, Stephen Reay wrote:
> >>
> >> > I may be missing something here..
> >> >
> >> > So far the issues are "how do we deal with a parameter for the actual
> >> > object, vs new properties to apply",  "should __clone be called before
> >> > or after the changes" and "this won't allow regular readonly
> properties
> >> > to be modified".
> >> >
> >> > Isn't the previous suggestion of passing the new property arguments
> >> > directly to the __clone method the obvious solution to all three
> >> > problems?
> >> >
> >> > There's no potential for a conflicting property name, the developer
> can
> >> > use the new property values in the order they see fit relative to the
> >> > logic in the __clone call, and it's inherently in scope to write to
> any
> >> > (unlocked during __clone) readonly properties.
> >>
> >> I did some exploratory design a few years ago on this front, looking at
> the implications of different possible syntaxes.
> >>
> >> https://peakd.com/hive-168588/@crell/object-properties-part-2-examples
> >>
> >> What that article calls "initonly" is essentially what became
> readonly.  The second example is roughly what this RFC would look like if
> the extra arguments were passed to __clone().  As noted in the article, the
> result is absolutely awful.
> >>
> >> Auto-setting the values while using the clone($object, ...$args) syntax
> is the cleanest solution.  Given that experimentation, I would not support
> an implementation that passes args to __clone and makes the developer
> figure it out.  That just makes a mess.
> >>
> >> Rob makes a good point elsewhere in thread that running __clone()
> afterward is a way to allow the object to re-inforce validation if
> necessary.  My concern is whether the method knows it needs to do the extra
> validation or not, since it may be arbitrarily complex.  It would also
> leave no way to reject the changes other than throwing an exception, though
> in fairness the same is true of set hooks.  Which also begs the question of
> whether a set hook would be sufficient that __clone() doesn't need to do
> extra validation?  At least in the typical case?
> >>
> >> One possibility (just brainstorming) would be to update first, then
> call __clone(), but give clone a new optional arg that just tells it what
> properties were modified by the clone call.  It can then recheck just those
> properties or ignore it entirely, as it prefers.  If that handles only
> complex cases (eg, firstName was updated so the computed fullName needs to
> be updated) and set hooks handle the single-property ones, that would
> probably cover all bases reasonably well.
> >
> >
> > I like where this is going but here is a variant that'd be even more
> capable:
> >
> > we could pass the original object to __clone.
>
> My proposal earlier was to pass the original object _and_ the values
> that were passed to the clone call, by reference.
>
And this would happen before those values are assigned to the object.
>
> class MyClass {
>   public function __construct(
>     public readonly int $x,
>     public readonly int $y,
>     public readonly int $z,
>   ) {}
>   public function __clone(object $original, array &$values): void {
>     // Set a value directly, and modify it.
>     if (isset($values['x'])) {
>       $this->x = $values['x'] * 10;
>       // Prevent that the same property is assigned again.
>       unset($values['x']);
>     }
>   }
> }
>
> $obj = new C(5, 7, 9);
> $clone = clone($obj, x: 2, y: 3);
> assert($clone->x === 20);  // x was update in __clone().
> assert($clone->y === 3);  // y was auto-updated after __clone().
> assert($clone->z === 9);  // z was not touched at all.
>

I'm not sure I understand, there might be missing bits to your idea, eg
where is visibility enforced? why is pass-by-ref needed at all?
Pass-by-ref makes me think this is a bad idea already :)

Also, WDYT of my simpler proposal itself? Wouldn't it cover all use cases?

Note that I don't see the need for operations like in your example
(transforming a value while cloning).
This looks like the job of a setter or a hook instead, not a cloner.


> >
> > The benefits I see:
> > - Allow implementing this validation logic you're talking about.
> > - Allow to skip deep-cloning of already updated properties (that's a
> significant drawback of the current proposal - deep cloning before setting
> is a potential perf/mem hog built into the engine) : guarding deep-cloning
> with a strict comparison would be enough.
> > - Allow implementing WeakMap that are able to clone weak-properties as
> objects are cloned.
> >
> > On this last aspect, I think it's new to the discussion but it's
> something I've always found very limiting when using weak-map: let's say
> some metadata are stored about object $foo in a weakmap, it's currently not
> possible to track those metadata across clones without using some nasty
> tricks. If __clone were given the original object, it's be easy to
> duplicate meta-data from $foo to $clone.
> >
> > I have just one concern significant with adding an argument to __clone:
> it'dbe a BC break to mandate this argument at the declaration level, and
> adding one right now generates an error with current versions of PHP.
> > However, I think we could (and should if confirmed) provide some FC/BC
> layer by allowing one to use func_get_args() in __clone. The engine could
> then verify at compile time that __clone has either one non-nullable
> "object" argument, or zero.
>
> This seems reasonable.
>
>
I'd be happy to know what Volker and Tim think about this? I read they
excluded any change to __clone in the RFC, but I think it should still be
possible to discuss this, especially if it provides the path to the desired
solution.

Nicolas

Reply via email to