-
-
Notifications
You must be signed in to change notification settings - Fork 205
PHP 8.3: New sniff to detect dynamic class constant fetch #1974
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
PHP 8.3: New sniff to detect dynamic class constant fetch #1974
Conversation
|
@jrfnl Please review when you are able. Thanks. |
|
Checklist per our discussions:
|
The three groups of tests are: - Explicitly targeted by the sniff and found on unsupported version - Same above, but not found on supported versions - Cases that are not the sniff's target, but using similar tokens or syntax that might throw false positives Added a parse error test case, since PHPCS can be used as a plugin, and so will run on code still being typed (live coding).
|
@jrfnl Ready for a second pass. I likely won't be around tomorrow evening so I don't mind comments in writing, unless there's something complex I need to understand. I will focus on incorporating your feedback to the other sniff PRs. I added a comment in the test fixtures for each line. Hopefully it can help with documenting test guidelines (putting words on things so you have less work). |
|
@jrfnl Would you mind giving this another look and merging if all is good? I'm hesitant to work on new sniffs until I understand what to aim for. |
jrfnl
left a comment
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.
Hi @afilina I really like where this is going. It's close, but it's not there yet.
The tests as they currently are, are not correctly testing what needs testing. When the testVersion changes have been made for which I left inline suggestions, you will see that with the current sniff code, the sniff throws a false positive.
This will need to be fixed.
Hope this review helps.
PHPCompatibility/Docs/Syntax/NewDynamicClassConstantFetchStandard.xml
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.inc
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.php
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.php
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.php
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.php
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.php
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.php
Outdated
Show resolved
Hide resolved
PHPCompatibility/Tests/Syntax/NewDynamicClassConstantFetchUnitTest.php
Outdated
Show resolved
Hide resolved
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
There has been a new PHPCSDevCS release, which is causing those. PR #1983 is open to handle that update. Rebasing will only fix the issues you are seeing after PR #1983 has been merged. (which is why that PR has the "high priority" label as until it is merged, other PRs are blocked due to CI failing) In the mean time, you can ignore those CS errors as long as they are not for the new files in this PR. |
@afilina The tests are failing now as predicted in my base review comment. To fix this, a change is needed to the sniff logic.
As things are, the sniff does not distinguish between the following: Foo::{$bar}(); // Supported since PHP 5,4
Foo::{$bar}; // Supported since PHP 8.3Also looks like the PHP 5.4 change which added support for Maybe we should open an issue to investigate the details of the PHP 5.4 change separately ? (I haven't found the relevant RFC yet, but only took a quick glance at the PHP 5.4 RFCs). |
|
With CI cancelling the actual tests due to CS issues, how would I know that my PR is ready to be merged, other than running the unit tests locally? I want to avoid manual review back-and-forth. Edit: feedback on the error message
I remember we spoke about a sniff for prohibiting uppercase booleans. Not sure it's fixable since a sniff doesn't look at the config of other sniffs for its message, but just wanted to point out that this small issue exists. |
CI doesn't cancel the test runs due to the CS issues. The tests run just fine as they are in a separate workflow, but they are failing: https://github.com/PHPCompatibility/PHPCompatibility/actions/runs/19445175583
I would always recommend running the tests locally (on a single PHP version) for any sniff related commit anyhow. CI will verify it against every supported combination, but it is rare for the tests for PHPCompatibility to fail on a single combination. In most cases, like here, it will fail for every single combination of PHP + PHPCS + Utils as there is something wrong in the sniff logic. |
|
@jrfnl Hmm, I may have misread the CI results then. It seemed like the test tasks appeared as cancelled seconds after the CS failed. Edit: I also wanted to apologize for not running the tests before asking for another review. I was caught in merging the suggestions and didn't consider this at the end. |
|
@afilina While trying to fall asleep last night, my brain came up with some additional code samples to run the tests with. Foo::{$bar}->prop;
Foo::{$bar}->method();
Foo::{$bar}?->prop;
Foo::{$bar}?->method();
Foo::{$bar}::CONSTANT_NAME;Still probably wouldn't go amiss to include the additional tests, if only to document that that syntax is now supported and that PHPCompatibility will flag it. |
PHPCompatibility/Sniffs/Syntax/NewDynamicClassConstantFetchSniff.php
Outdated
Show resolved
Hide resolved
| return; | ||
| } | ||
|
|
||
| $closingBracket = $phpcsFile->findNext(\T_CLOSE_CURLY_BRACKET, $nextNonEmpty + 1); |
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.
There is a better way to do this.
As things are, the findNext() call may return false during live coding Foo::{$bar (and yes, this test will need to be added as a separate parse error test). This false would now be turned into 1 via the $closingBracket + 1 on the next line, which is a bug...
Additionally, what about: Foo::{{$bar->name}()} ? Now, the sniff would find the wrong curly as it doesn't take the nested curlies into account.
The good news is that brackets will create an extra detail entry in the token stream, which means you can find the close curly like this:
$opener = $nextNonEmpty;
if (isset($tokens[$opener]['bracket_closer']) === false) {
// Live coding or parse error. Bow out.
// To think over: or should this throw an error ?
return;
}
$closer = $tokens[$opener]['bracket_closer'];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.
This is why arrays are so hard to work with :)
Thanks for the suggestion.
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.
or should this throw an error ?
Normally we skip parse errors. And since it prevents us from definitively detect the sniff's target issue, we shouldn't report anything. That's how I came to expect PHPCompatibility to work.
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.
This is why arrays are so hard to work with :)
Not sure I understand that jibe. The problem was with an incorrect findNext(). Not with an array which actually contained useful information.
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.
Going back to Foo::{{$bar->name}()}, this is another parse error, but it looks fine to the sniff, which would basically see Foo::{...} with no following parenthesis. So not only do we need to match the right closer, we need to make sure that there is no opener immediately following an opener. I have to admit I'm a bit lost as to how far I need to dig into this entire category of parse errors.
Edit: made an attempt in the commit below. After {, PHP expects an expression. We don't have a simple way to say "everything between this and that pointer is a valid expression". So I just limit to { so we don't go overboard with this sniff.
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.
Going back to
Foo::{{$bar->name}()}, this is another parse error, but it looks fine to the sniff, which would basically seeFoo::{...}with no following parenthesis. So not only do we need to match the right closer, we need to make sure that there is no opener immediately following an opener.
I used the Foo::{{$bar->name}()} example just to highlight the logic error in the token walking.
Unless there are currently explicit rules in PHP about what is allowed between the curlies for the new syntax, I'm fine with not checking between the curlies.
I have to admit I'm a bit lost as to how far I need to dig into this entire category of parse errors.
It's always hard to determine where to draw the line. As a rule of thumb: when your own fantasy of syntaxes to take into account runs out ;-) I know that is not a hard or solid guideline, but sometimes it's the best we can do.
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.
Let me know if there are any other blockers on this PR.
…sts to their own test files
…move test down ... to comply with expected order of the test methods.
* Add missing line numbers to data provider * Add one extra test case
* Fix tag order in test docblocks. * Use proper punctuation in inline comments in sniff. * Use FQN class refs in docblocks.
jrfnl
left a comment
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.
@afilina Thank you for all your work on this.
I've now merged the current develop branch in to allow for this PR to get a passing build.
I've also made a few more tweaks, most of which were discussed in review comments already. I've pushed those in separate commits so you can see what I've done.
I'm happy for this PR to be merged now and will include it in the 10.0.0-alpha2 release.
Part of this effort: #1589
Adding a sniff for new syntax to dynamically fetch class constants
C::{$name}. Existing sniffs were not fit for this purpose, and adding things there would have made them unnecessarily hard to maintain.Implemented in a similar fashion to other new syntax sniffs.
Dynamic class constant fetch is not available in PHP 8.2 or earlier.Founderror code.Edit: we ended up checking the corresponding closing bracket. It was needed to weed out some false positives.