Skip to content

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

Closed
wants to merge 6 commits into from
Closed

Conversation

kocsismate
Copy link
Member

@kocsismate kocsismate commented Apr 18, 2021

@kocsismate kocsismate added the RFC label Apr 18, 2021
@kamil-tekiela
Copy link
Member

Why was this not supported before?

@kocsismate
Copy link
Member Author

Why was this not supported before?

I honestly don't have an idea. Maybe it didn't seem important enough (?).

@mvorisek
Copy link
Contributor

https://3v4l.org/EYL34 - the final modifier is allowed only for methods and classes

That error should be updated as well.

@reyadkhan

This comment has been minimized.

@kocsismate

This comment has been minimized.

@reyadkhan

This comment has been minimized.

@drealecs

This comment has been minimized.

@krakjoe
Copy link
Member

krakjoe commented May 11, 2021

@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.

@kocsismate
Copy link
Member Author

could you update the opening comment with a link to the rfc, so it's front and center please.

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. :)

@kocsismate kocsismate force-pushed the final-const branch 3 times, most recently from 62a329f to 30b23c7 Compare May 13, 2021 22:22

?>
--EXPECTF--
Fatal error: Private constant Foo::A cannot be final as it is never overridden in %s on line %d
Copy link
Contributor

@TysonAndre TysonAndre May 20, 2021

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

Copy link
Member Author

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?

@nikic
Copy link
Member

nikic commented May 28, 2021

The case of interfaces is interesting, and I think missing some test coverage. First case:

interface I1 {
    const C = 1;
}
interface I2 {
    const C = 2;
}
class C implements I1, I2 {
}

This should (and does) error, because the constant is inherited from two different interfaces.

interface I1 {
    const C = 1;
}
interface I2 {
    const C = 2;
}
class C implements I1, I2 {
    const C = 3;
}

This should not (and does not) error, because the constant is explicit redeclared.

interface I1 {
    const C = 1;
}
interface I2 {
    const C = 2;
}
interface I3 extends I1, I2 {
    const C = 3;
}

I believe that by analogy with the previous case, this shouldn't error, but currently does.

class C {
    const C = 1;
}
interface I {
    const C = 2;
}
class C2 extends C implements I {}

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.

@nikic nikic added this to the PHP 8.1 milestone Jul 1, 2021
@nikic
Copy link
Member

nikic commented Jul 1, 2021

Ping :) Please tell me if you need help.

@kocsismate
Copy link
Member Author

kocsismate commented Jul 1, 2021

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 ^^

@kocsismate
Copy link
Member Author

kocsismate commented Jul 3, 2021

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?

@nikic
Copy link
Member

nikic commented Jul 6, 2021

@kocsismate Does this look right to you?

@kocsismate
Copy link
Member Author

Does this look right to you?

Yeah, very nice! :)

@kocsismate
Copy link
Member Author

Closing via a5360e8

@kocsismate kocsismate closed this Jul 6, 2021
@kocsismate kocsismate deleted the final-const branch July 6, 2021 19:47
jrfnl added a commit to PHPCompatibility/PHPCompatibility that referenced this pull request Mar 8, 2022
> 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
DanielEScherzer added a commit to DanielEScherzer/php-src that referenced this pull request Sep 5, 2024
There was a whole RFC about this, but the implementation in php#6878 seems to have
missed updating the documentation
iluuu1994 pushed a commit that referenced this pull request Sep 5, 2024
…H-15764)

There was a whole RFC about this, but the implementation in #6878 seems to have
missed updating the documentation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants