Skip to content

Proposal: abstract constants #11223

@Lenald

Description

@Lenald

Description

User Story

As a PHP developer, I want to be able to declare abstract constants inside a class so that I can enforce their implementation in subclasses, either by their own implementation or through interface implementation. This will allow me to safely and more obvious use late static binding to reference these constants within the class and ensure their proper implementation in subclasses.

Behavior

If an abstract constant is not implemented in a subclass, either on its own or through interface implementation, then the subclass should be declared as abstract. Otherwise, a fatal error should be thrown during class loading or instance creation, with a message such as “Fatal error: Class [ClassName] contains N abstract constant(s) and must therefore be declared abstract or implement the remaining constants ([AbstractConstantName]) in [ClassFilePath] on line [LineNumberOfError]”. Direct reads of abstract constants should also trigger a fatal error with a message such as “Fatal error: Direct read of abstract constant [ClassName]::[AbstractConstantName] in [ClassFilePath] on line [LineNumberOfError]”. When an abstract constant is declared, its value should not be set, similar to how abstract methods are declared.

Purposes

This feature would be useful to enforce the implementation of a constant in subclasses, without the need for workarounds such as declaring this constant in the parent class with a default value and checking for overrides in the subclass.

Example Code

<?php

abstract class Parent
{
    abstract public const SOMETHING;

    public function foo(): string
    {
        echo static::SOMETHING . PHP_EOL;
    }
}

class ChildImplementsOnTheirOwn extends Parent
{
    public const SOMETHING = 'Implemented by Child class';
}

interface SomethingInterface
{
    public const SOMETHING = 'Implemented by Interface';
}

class ChildImplementsByInterface extends Parent implements SomethingInterface
{
}

class NotImplemented
{
}

Parent::SOMETHING; //Fatal: Direct read of abstract

ChildImplementsOnTheirOwn::SOMETHING; //'Implemented by Child class'
(new ChildImplementsOnTheirOwn())->foo(); //'Implemented by Child class'

SomethingInterface::SOMETHING; //'Implemented by Interface'
ChildImplementsByInterface::SOMETHING; //'Implemented by Interface'
(new ChildImplementsByInterface())->foo(); //'Implemented by Interface'

NotImplemented::SOMETHING; //Fatal: Must implement or be declared as abstract
$notImplemented = new NotImplemented(); //Fatal: Must implement or be declared as abstract
(new NotImplemented())->foo(); //Fatal: Must implement or be declared as abstract (must be thrown already from __construct())

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions