Hi Rob On Thu, Jul 31, 2025 at 10:48 AM Rob Landers <rob@bottled.codes> wrote: > > Currently, this is not allowed by PHP: > > class Foo { > public function __construct( > public string &$ref { get => $this->ref ?? 'null'; set => $this->ref = > $value; } > ) {} > } > > After the release, I'd like to propose an RFC that allows using references > with hooks:
As we've considered references extensively during the hooks RFC, allow me to add some context. > this will probably necessitate a new zval type, determined at runtime (it > will not be exposed to users). The impact for new zval types is gigantic, and it's been avoided for decades. I don't think it's technically necessary either. We're already recording zend_reference.sources, which is a list of properties that store the reference. This is used for type coercion when assigning to a reference that may be stored in a typed property. class C { public int $prop; } $c = new C(); $prop = 42; $c->prop = &$prop; $prop = '43'; var_dump($prop); // int(43) You may be able to use the same mechanism for set hooks. This would need to be extended to store the actual object containing the reference, so that the set hook may be invoked. However, there are some issues. For example, what do you do when a reference is assigned to multiple hooked properties? class C { public int $prop1 { set => $value + 1; } public int $prop2 { set => $value + 2; } } $c = new C(); $prop = 42; $c->prop1 = &$prop; $c->prop2 = &$prop; $prop = 43; // What happens now? Typed properties handle type conflicts gracefully [^1], but graceful handling for hooks is less clear because each hook can transform the assigned value. You might allow assignment only when the reference is bound to a single hooked property, but then this isn't a general solution. I suppose you may also require all set hooks to assign the reference to an identical value. Another current limitation is reference assignment. `$c->prop1 = &$prop;` from above doesn't actually work. That's because hooks currently allow &get, i.e. retrieving the reference stored in a hooked property (`$prop = &$c->prop1`), but they don't allow setting the property reference, which is semantically distinct. set(&value) is not sufficient because the hook implementation must know whether to assign to the backing store through a direct assignment, or =&. set(&value, bool $byRef) would work, but is quite clunky. You also mention arrays. This approach does not solve the issues we've outlined in the RFC [^2]. In particular, indirect modification may still hide mutations from set hooks. Even if we can fix this and make every mutation call the set hook, the significant ergonomic issues of understanding _how_ the array changed remain, along with performance issues due to array separation. Disregarding arrays, this approach might not be too complex. However, given that arrays are by far the most used type when it comes to references, them being exempt makes this feature far less useful. That's the main reason we didn't pursue this idea further, and I remain quite convinced that arrays are unworkable. Ilija [^1]: https://3v4l.org/defVI [^2]: https://wiki.php.net/rfc/property-hooks#arrays