====== PHP RFC: #[\Override] for class constants ====== * Version: 0.3 * Date: 2026-03-13 * Author: Daniel Scherzer, daniel.e.scherzer@gmail.com * Status: Under Discussion * Implementation: https://github.com/php/php-src/pull/20478 * Discussion thread: https://news-web.php.net/php.internals/130504 ===== Introduction ===== In PHP 8.3, the #[\Override] attribute was added ([[rfc:marking_overriden_methods]]). In PHP 8.5, it was extended to allow use on properties ([[rfc:override_properties]]). This RFC proposes to further expand the attribute to target class constants as well. Class constants can override constants defined in parent classes, which can create a footgun. While it has been possible to mark a class constant as final since PHP 8.1 ([[rfc:final_class_const]]), when a class constant is overridden it is not always clear if the intention is to override a class constant in the parent class, or to define a new (unrelated) constant. The #[\Override] attribute has already solved this problem by making it explicit (for methods and properties) that an override is intentional, and triggers an error when no override is being performed. This RFC expands the same functionality to class constants. Enum cases, which are internally a special type of class constant, are treated similarly - when marked with #[\Override] they must be overriding an inherited interface constant. See the "Rejected Features" section for further details. ===== Proposal ===== Allow the #[\Override] attribute to be used on class constants, with the same validation as methods and properties (modulo the fact that there are no abstract constants the way there are properties and methods): * Public and protected constants of a parent class or implemented interface satisfy #[\Override]. Private constants do not satisfy the attribute. * #[\Override] is ignored on traits, but constants 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 constant requires the existence of a matching constant in a parent class or implemented interface. * #[\Override] works as expected on anonymous classes. * #[\Override] works as expected on interfaces: a matching constant needs to exist in a parent interface. * #[\Override] works as expected on enums: * Class constants marked with #[\Override] need to override a matching constant in a parent interface * Enum cases (which internally are class constants) marked with #[\Override] also need to override a matching constant in a parent interface. While overriding constants with enum cases is not very common, all the more reason to allow making that intention explicit via the attribute. ==== Examples ==== Simple example: ===== Backward Incompatible Changes ===== There should be no backwards incompatibilities from this change - the #[\Override] attribute previously always caused errors on class constants (because it was not supported), now it will only sometimes cause errors (when nothing is being overridden). Note that for interaction with #[\DelayedTargetValidation], class constants work the same as properties and methods - even if #[\DelayedTargetValidation] is present, on PHP 8.6+ the #[\Override] attribute on class constants will still result in an error if the class constant is not overriding anything. ===== Proposed PHP Version(s) ===== Next minor version (PHP 8.6). ===== RFC Impact ===== ==== To the Ecosystem ==== IDEs and static analyzers will likely want to extend their rules for #[\Override] to constants. ==== To Existing Extensions ==== Extensions might want to add the attribute to their constants where appropriate. ==== To SAPIs ==== None ===== Open Issues ===== None ===== Voting Choices ===== Extend #[\Override] to target class constants? ---- Primary Vote requiring a 2/3 majority to accept the RFC: * Yes * No * Abstain ===== Patches and Tests ===== https://github.com/php/php-src/pull/20478 ===== Implementation ===== After the RFC is implemented, this section should contain: - the version(s) it was merged into - a link to the git commit(s) - a link to the PHP manual entry for the feature ===== References ===== * [[rfc:override_properties]] * [[rfc:marking_overriden_methods]] * [[rfc:final_class_const]] ===== Rejected Features ===== Keep this updated with features that were discussed on the mail lists. ==== Prohibit #[\Override] on enum cases ==== A previous version of this RFC had the following open issue: > Currently, enum cases can override class constants inherited from an interface. How should #[\Override] work for enum cases? Options include > > * Always reject using #[\Override] on an enum case, saying that the attribute does not target enum cases > * Treat enum cases the same as class constants, and validate that they override an inherited constant Following discussion on the mailing list, the RFC author decided to go with the second option - to treat enum cases the same as class constants. This aligns with the behavior of other attributes that target class constants, like #[\Deprecated] - internally, enum cases are just a special type of class constant. While it is unlikely that enum cases are frequently overriding inherited constants, that rarity makes it all the more important that when a case //does// override an inherited class constant, the overriding is made explicit by allowing the #[\Override] attribute. ===== Changelog ===== If there are major changes to the initial proposal, please include a short summary with a date or a link to the mailing list announcement here, as not everyone has access to the wikis' version history. * v0.1: created * v0.2: identify open issue regarding enum cases declared as overriding inherited constants * v0.3: resolve that issue - enum cases can be marked as #[\Override], which requires a matching constant to exist on an interface