====== PHP RFC: Extend #[\Override] to target properties ====== * Version: 1.0 * Date: 2025-07-07 * Author: Jiří Pudil, me@jiripudil.cz * Status: Under Discussion * Implementation: https://github.com/php/php-src/pull/19061 ===== Introduction ===== This is a follow-up to [[https://wiki.php.net/rfc/marking_overriden_methods|a previous RFC]] which introduced the ''#[\Override]'' attribute to explicitly express the intent of a method to override a parent method or implement an interface. During inheritance, PHP then checks that the method actually exists in the parent hierarchy or in one of the implemented interfaces. The original RFC explicitly excluded properties:
As of now properties may not be part of an interface and thus only properties of a parent class can be overridden. The type of properties is enforced to be invariant and properties do not have behavior attached. A property can only ever be overridden by a compatible property with possibly added attributes.A lot has changed in PHP 8.4 and, as a result, some of these premises are no longer true: * Abstract properties can be declared in classes and interfaces. * Under specific circumstances, property types may be covariant during inheritance. * Properties may include behaviour in the form of hooks. (This is not relevant here, though. Since hooks are implemented as methods, they already support the ''#[\Override]'' attribute.) Overall, these changes have allowed properties to become a more prominent part of the public API of a class or an interface, and I think it warrants the original decision to be revisited. ===== Proposal ===== I propose to extend the target of the ''#[\Override]'' attribute to include properties. If this attribute is added to a property, the engine validates that a property with the same name exists in a parent class or any of the implemented interfaces and emits a compilation error if no such property exists. The semantics are the same as with methods: * Public and protected properties of a parent class or implemented interface satisfy ''#[\Override]''. * Abstract properties satisfy ''#[\Override]''. * Static properties behave as instance properties. * Private properties of a parent class do not satisfy ''#[\Override]'' because they are not part of the public API. * ''#[\Override]'' is ignored on traits, but properties from a used trait behave as if the property definition was copied and pasted into the target class. Specifically the ''#[\Override]'' attribute on a trait property requires the existence of a matching property in a parent class or implemented interface. * ''#[\Override]'' works as expected on anonymous classes. * ''#[\Override]'' works as expected on interfaces: a matching property needs to exist in a parent interface. * ''#[\Override]'' in this context does not apply to enums because they are not allowed to have properties. * ''#[\Override]'' can be attached to promoted properties. ===== Examples =====