-
Couldn't load subscription status.
- Fork 8k
Description
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())