rfc:final_class_const

This is an old revision of the document!


PHP RFC: Final class constants

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

Add support for final class constants? The vote requires 2/3 majority to be accepted.

rfc/final_class_const.1620141146.txt.gz · Last modified: 2021/05/04 15:12 by kocsismate