> On 18. Jul 2025, at 23:48, Eric Norris <eric.t.nor...@gmail.com> wrote:
> 
> On Fri, Jul 18, 2025 at 12:01 PM Rob Landers <rob@bottled.codes 
> <mailto:rob@bottled.codes>> wrote:
>> 
>> 
>> 
>> On Fri, Jul 18, 2025, at 17:25, Tim Düsterhus wrote:
>> 
>> Hi
>> 
>> On 7/14/25 15:38, Larry Garfield wrote:
>>> Thanks, Ilija.  You expressed my concerns as well.  And yes, in practice, 
>>> readonly classes over-reaching is the main use case; if you're marking 
>>> individual properties readonly, then just don't mark the one that has a 
>>> hook on it (use aviz if needed) and there's no issue.
>> 
>> A readonly class is not just a convenience shortcut to mark each
>> individual property as readonly. It has important semantics of its own,
>> because it forces child classes to also be readonly. And even for final
>> classes it communicates to the user that "I won't be adding non-readonly
>> properties to the class".
>> 
>> 
>> Wasn’t that the entire point of readonly classes? Because it was painful to 
>> write readonly for every property. Then if a property is readonly, the 
>> inherited property is also readonly, so, by extension: a class extending a 
>> readonly class is also readonly.
>> 
>> There’s no “communication” here; just logic.
>> 
>> 
>> Marking a class as readonly must therefore be a deliberate decision,
>> since it affects the public API of your class and in turn also user
>> expectations.
>> 
>> 
>> Not really. I can remove the readonly designation and manually mark every 
>> property as readonly. The behavior of the class doesn’t magically change. 
>> Or, at least, I hope it doesn’t.
>> 
>> 
>>> Perhaps we're thinking about this the wrong way, though?  So far we've 
>>> talked as though readonly makes the property write-once.  But... what if we 
>>> think of it as applying to the field, aka the backing value?
>> 
>> I think of readonly from the view of the public API surface of an
>> object. The property hooks RFC was very explicit in that property hooks
>> are intended to be “transparent to the user” and can be added without
>> breaking the public API. In other words: Whether or not a property is
>> implemented using a hook should be considered an implementation detail
>> and as a user of a class I do not care whether there is a backing value
>> or not.
>> 
>>> So readonly doesn't limit calling the get hook, or even the set hook, 
>>> multiple times.  Only writing to the actual value in the object table.  
>>> That gives the exact same set of guarantees that a getX()/setX() method 
>>> would give.  The methods can be called any number of times, but the stored 
>>> value can only be written once.
>> 
>> As a user of a class the "backing table" is mostly inaccessible to me
>> when interacting with objects. It's only exposed via var_dump() and
>> serialize(), the former of which is a debug functionality and the output
>> of latter not something I must touch.
>> 
>>> It would not guarantee $foo->bar === $foo->bar in all cases (though that 
>>> would likely hold in the 99% case in practice), but then, $foo->getBar() 
>>> === $foo->getBar() has never been guaranteed either.
>> 
>> Properties and methods are something different. For methods there a
>> reasonable expectation that *behavior* is associated with them, for
>> properties there is not.
>> 
>> 
>> Unless I missed something. Hooks are fancy methods? There is nothing 
>> intrinsic about object properties. There is nothing that says two calls to 
>> the same property’s getters are going to result in the same values. There is 
>> asynchronous php, declare ticks, etc. especially in the case of globals, 
>> there is no guarantee you even have the same object. At the end of the day, 
>> it is up to the programmer building that system / program to provide those 
>> guarantees— not the language.
> 
> I do think that, without any additional information, it would be
> reasonable to assume that `$foo->bar === $foo->bar`, i.e. there would
> not be side-effects until you've called a method or written to the
> object in some way. So I share Tim's opinion here, but I do agree that
> with hooks available this is not actually a guarantee. You could
> certainly have a `$foo->random_value` property and document that it
> will be different each time you call it.
> 
> That said, once the programmer has added the readonly designation to a
> property, I do think that something says that two calls to the same
> property will result in the same values - the readonly designation. I
> disagree with the point that it's not up to the language - the
> language should provide an affordance for enforcing programmer intent,
> and I see no reason to even have a readonly designation if we're going
> to make it easily circumventable or otherwise just a "hint".
> 
> It seems that one common counterpoint to the "let's not make it
> circumventable" argument is to point out that it's already
> circumventable via __get. I agree with Claude that this is not a
> justification for making it *easier* to circumvent. I would also like
> to note that the original RFC
> (https://wiki.php.net/rfc/readonly_properties_v2#unset) seems to allow
> this behavior *for the purpose of lazy initialization*. With an `init`
> hook, we'd have solved this problem, and could deprecate the `__get`
> hack for `readonly` properties / classes.
> 
> Nicolas Grekas said "__get is certainly not legacy; removing it would
> break many use cases without proper alternatives.", but note that I'm
> only suggesting we could maybe deprecate __get for `readonly`
> properties once we had an `init` hook - I'm not proposing deprecating
> it generally. Without a counterexample, I don't think there would be
> another reason for `__get` to work with `readonly` properties.

Hey all,

I allow myself to answer in one single mail, instead to all of you individually.

Honestly, I didn’t expect that this RFC will be THAT controversial. 😅
However, I get it. There are good arguments on either side. 

I did hope that the “implicit cache” is a decent middle ground, but that also 
didn’t work out as I thought.

As mentioned earlier, this is my very first RFC. I am at a point where I am a 
bit overwhelmed.

That said, Larry and I heard you and already decided to offer a split vote to 
enable us to at least land “set only” in 8.5. 
If we didn’t misunderstood it, then y’all agreed on `set` (only) should be 
allowed?

This would IMHO already be a huge improvement compared to now; and a low 
hanging fruit. 
Not exactly what I wanted, but it is what it is.
Long story short. We simply don’t have the time to get `init` sorted before 
feature freeze. 

I offer to follow up with a “readonly `init` hook” RFC for 8.6 to sort the rest.

I’d appreciate if voters could settle on a yes for “set only” for 8.5.

Wdyt? Would this help to get closer to closing the discussion?

Cheers,
Nick

Reply via email to