Re: [RFC[ Property accessor hooks, take 2
| From: | Rowan Tommins [IMSoP] | Date: | Sat, 16 Mar 2024 08:32:39 +0000 |
| Subject: | Re: [RFC[ Property accessor hooks, take 2 | ||
| References: | 1 2 3 4 5 6 7 8 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-122653@lists.php.net to get a copy of this message | ||
On 16 March 2024 00:19:57 GMT, Larry Garfield <larry@garfieldtech.com> wrote:
>Well, reading/writing from within a set/get hook is an obvious use case to support. We cannot
>do cached properties easily otherwise:
>
>public string $expensive {
> get => $this->expensive ??= $this->compute();
> set {
> if (strlen($value) < 50) throw new Exception();
> $this->expensive = $value;
> }
>}
To play devil's advocate, in an implementation with only virtual properties, this is still
perfectly possible, just one declaration longer:
private string $_expensive;
public string $expensive {
get => $this->_expensive ??= $this->compute();
set {
if (strlen($value) < 50) throw new Exception();
$this->_expensive = $value;
}
}
Note that in this version there is an unambiguous way to refer to the raw value from anywhere else
in the class, if you wanted a clearAll() method for instance.
I can't stress enough that this is where a lot of my thinking comes from: that backed
properties are really the special case, not the default. Anything you can do with a backed property
you can do with a virtual one, but the opposite will never be true.
The minimum version of backed properties is basically just sugar for that - the property is still
essentially virtual, but the language declares the backing property for you, leading to:
public string $expensive {
get => $field ??= $this->compute();
set {
if (strlen($value) < 50) throw new Exception();
$field = $value;
}
}
I realise now that this isn't actually how the current implementation works, but again I wanted
to illustrate where I'm coming from: that backed properties are just a convenience, not a
different type of property with its own rules.
> Being the same also makes the language more predictable, which is also a design goal for this
> RFC. (Hence why "this is the same logic as methods/__get/other very similar thing" is
> mentioned several times in the RFC. Consistency in expectations is generally a good thing.)
I can only speak for myself, but my expectations were based on:
a) How __get and __set are used in practice. That generally involves reading and writing a private
property, of either the same or different name from the public one; and that private property is
visible everywhere equally, no special handling based on the call stack.
b) What happens if you accidentally cause infinite recursion in a normal function or method, which
is that the language eventually hits a stack depth limit and throws an error.
So the assertion that the proposal was consistent with expectations surprised me. It feels to me
like something that will seem surprising to people when they first encounter it, but useful once
they understand the implications.
Regards,
Rowan Tommins
[IMSoP]