-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add support for final constants #6878
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Why was this not supported before? |
I honestly don't have an idea. Maybe it didn't seem important enough (?). |
https://3v4l.org/EYL34 - That error should be updated as well. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@kocsismate could you update the opening comment with a link to the rfc, so it's front and center please. PS, this needs a rebase. |
Yeah, of course! I've just done so. Thanks for the heads up with with the rebase, I'll have to implement the second half of the RFC, so I'll do it soon when I manage to come back to it. :) |
62a329f
to
30b23c7
Compare
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Private constant Foo::A cannot be final as it is never overridden in %s on line %d |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really a major issue since it's impossible for existing code to use private final const
so there's no bc break.
It seems allowed to override private constants with public constants and static:: will use the public constants, e.g. in php 7.4
Also, the fact that private final
is forbidden isn't documented in the rfc right now? https://wiki.php.net/rfc/inheritance_private_methods
php > class A { public const A = 'const A::A'; public static function dump() { var_dump(static::A); } }
php > class B extends A { public const A = 'const B::A'; }
php > B::dump();
string(10) "const B::A"
php > class X { private function foo() { echo "in X::foo\n";} public function dump() { $this->foo(); } }
php > class Y extends X { public function foo() { echo "In Y::foo\n"; } }
php > (new Y())->dump();
in X::foo
I guess updating the issue message may be better, e.g. as it would prevent subclasses from accessing a constant of that name
but I don't know why that would be a compelling reason to forbid private final
- it'd also be a compile error if those subclasses tried to declare the constant to override protected final
Somewhat reminds me of https://externals.io/message/110540#110576
LGTM otherwise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First of all, thank you for the review!
Also, the fact that private final is forbidden isn't documented in the rfc right now?
Yeah, this is quite unfortunate... I realized that it's not documented just after starting the vote. :(
I don't know why that would be a compelling reason to forbid private final - it'd also be a compile error if those subclasses tried to declare the constant to override protected final
The reason why final private
is forbidden is to be consistent with https://wiki.php.net/rfc/inheritance_private_methods indeed. So In my opinion (which might be wrong of course) if private methods (- constructors) cannot be final then the same should apply for constants. Unfortunately, I'm not 100% sure what exact issue is that you see, so could you please clarify it?
The case of interfaces is interesting, and I think missing some test coverage. First case:
This should (and does) error, because the constant is inherited from two different interfaces.
This should not (and does not) error, because the constant is explicit redeclared.
I believe that by analogy with the previous case, this shouldn't error, but currently does.
Here we have two constants, one coming from the parent class, one from the interface. Currently it doesn't error and uses the value from the class. I think this should error. I suspect the fact that interfaces may introduce "multiple parent constants" might have been the original reason why we had the inheritance restriction there. I hadn't considered this before. As outlined above, I think we can have reasonable behavior here, but the currently implemented one isn't correct. |
Ping :) Please tell me if you need help. |
Thanks for the offer, I'll definitely ask for help if I am stuck :) TBH I don't really have much free time these days, so I haven't yet tried to fix the issues you pointed out. I'm going to take a stab this weekend, unless I completely get passed out by the 2nd vaccine ^^ |
I addressed all the review comments, except for the most important one :( I just couldn't find out how to adjust the inheritance rules. Or should we track whether a constant was inherited when adding them to the constant table (e.g. by using a new flag)? Or is it still not enough to do? |
@kocsismate Does this look right to you? |
Yeah, very nice! :) |
Closing via a5360e8 |
> Added support for the final modifier for class constants. Also, interface constants become overridable by default. New sniff to detect this new feature. Note: the sniff does not do anything special for non-final interface constants which previously were not overridable. Includes unit tests. Includes docs. Refs: * https://wiki.php.net/rfc/final_class_const * https://www.php.net/manual/en/migration81.new-features.php#migration81.new-features.core.final-constants * https://www.php.net/manual/en/language.oop5.final.php#language.oop5.final.example.php81 * php/php-src#6878 * php/php-src@a5360e8
There was a whole RFC about this, but the implementation in php#6878 seems to have missed updating the documentation
RFC: https://wiki.php.net/rfc/final_class_const