Dear PHP developers,
I'm contemplating the creation of an RFC to add support for abstract
constants to PHP, and I'm looking for some initial feedback from you
before doing so (as stated in the wiki).
The Concept
The proposal would be to allow abstract classes and traits to declare
constants with the |abstract| keyword, which would require non-abstract
implementers to define such constant, most likely such constants would
be typed.
With abstract class constants we'd have piece of data defined in the
code which can be accessed both dynamically and statically in abstract
classes and traits, enforced by design.
Previous discussion and changes since then
As far as I've been able to find, this idea was discussed back in 2017
in the [PHP-DEV] Constants and Access Modifiers
https://marc.info/?t=150913772500003&r=1&w=2 thread.
Quite a few things discussed in that thread have changed, I'd like to
remark:
- Classes allow access to (overriden) constants via |self::CONSTANT|
and |static::CONSTANT|. - |readonly| properties have been added in PHP 8.1
https://wiki.php.net/rfc/readonly_properties_v2. - Constants can be defined as |final| since PHP 8.1
https://wiki.php.net/rfc/final_class_const. - Constants can have types since PHP 8.3
https://wiki.php.net/rfc/typed_class_constants.
I'm unaware of any other debates on the topic, if you know of any
relevant ones, feel free to bring them up on your reply.
Use cases: examples
- An abstract base class |DBTable| which requires a table name and
possibly definitions for columns. - A trait |EmitsLogs| which requires a tag that is prepended to log
messages.
If we're extending the base or using the trait in a "static" manner,
for example in a Model-like class, I'd argue that we'd want to define
them as constants, as we want to ensure that the value is defined by the
coder and does not change.
- For example, changing a table name during a transaction could lead to
unexpected results, or being able to change a logging tag could
compromise traceability.
The class and trait use this constant in some method, which will
indubitably fail if it isn't defined, which we could conveniently
enforce with |abstract|.
It'd be quite practical to access the table name of a |DBTable|
implementer without instantiating the class to, for example, perform
some related operation on another table (or perform a JOIN).
Implementation in PHP
Even though some (or all) functionality of abstract class constants
could be implemented via class reflection to ensure there's a valid
constant defined in implementers, this check would need to be present in
base-class or trait constructors and in any functions which access the
constants statically.
A feature which would provide similar (or the same) functionality,
|static readonly| properties are explicitly not allowed.
In my opinion, implementing this natively would be more practical and
convenient for both coders and tooling which parses PHP source code.
Initial feedback
I'd love to know what you think about the proposal. Would you be alright
with it?
If so, is there any suggestions or questions that should be brought up
before drafting a RFC?
If not, I'd be quite interested in knowing why.
Lastly, as a completely unrelated personal note, I'd like to thank all
of you for your work on this fantastic programming language, which I've
enjoyed dearly the past few years.
Thank you for your time and consideration,
Eloi Montañés.