====== PHP RFC: Final class constants ====== * Date: 2021-04-23 * Author: Máté Kocsis * Status: Implemented * Implementation: https://github.com/php/php-src/pull/6878 * Target Version: PHP 8.1 ===== Introduction ===== Currently, class constants are always overridable by child classes. This causes a few smaller caveats: First of all, the engine can't optimize class constant references when late static binding is involved, so it has to pessimistically assume that ''FOO'' is overridden in case of ''static::FOO'' or ''$this::FOO'' invocations. What's more important is that class constants are not guaranteed to stay constant. Even if the declaring class always references them by using ''self::'', doing so won't prevent a child class from changing their value or even their type, unless the parent is a final class. Although constants not being constants is usually considered only as a theoretical problem, being able to add a ''final'' modifier would make the intention explicit that child classes shouldn't try to override them (e.g. because the parent doesn't use late static binding). A related interesting fact is that interface constants are already ''final'': interface I { public const X = "i"; } class C implements I { public const X = "bar"; } // Fatal error: Cannot inherit previously-inherited or override constant X from interface I This leads to a weird inconsistency. By introducing an intermediate class, overriding still becomes possible: interface I { public const X = "i"; } class C implements I { } class D extends C { public const X = "d"; } // No error ===== Proposal ===== The final modifier can be added to class constants. Doing so prevents overriding of a constant: class Foo { final public const X = "foo"; } class Bar extends Foo { public const X = "bar"; } // Fatal error: Bar::X cannot override final constant Foo::X Besides, interface constants would become overridable by default, and the ''final'' modifier could be used to retain the original behavior. interface I { public const X = "i"; final public const Y = "i"; } class C implements I { public const X = "c"; // Overriding I::X is possible public const Y = "c"; // Overriding I::Y is not possible } // Fatal error: C::Y cannot override final constant I::Y ===== Reflection ===== A ''ReflectionClassConstant::isFinal()'' method is added in order to be able to retrieve if a constant is final. ===== Backward Incompatible Changes ===== None. ===== Vote ===== Voting started on 2021-05-19 08:00 UTC and ends 2021-06-02 08:00 UTC. The vote requires 2/3 majority to be accepted. * Yes * No