-
-
Notifications
You must be signed in to change notification settings - Fork 204
PHP 8.1: New PHPCompatibility.Classes.NewFinalClassConstants
sniff
#1317
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
PHPCompatibility/Docs/Classes/NewFinalClassConstantsStandard.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?xml version="1.0"?> | ||
<documentation title="New final class constants"> | ||
<standard> | ||
<![CDATA[ | ||
Class constants can be declared as final since PHP 8.1. | ||
]]> | ||
</standard> | ||
<code_comparison> | ||
<code title="Cross-version compatible: not using the final modifier."> | ||
<![CDATA[ | ||
class Foo { | ||
const BAR = 10; | ||
} | ||
]]> | ||
</code> | ||
<code title="PHP >= 8.1: using the final modifier."> | ||
<![CDATA[ | ||
class Foo { | ||
<em>final</em> const BAR = 10; | ||
} | ||
]]> | ||
</code> | ||
</code_comparison> | ||
</documentation> |
80 changes: 80 additions & 0 deletions
80
PHPCompatibility/Sniffs/Classes/NewFinalClassConstantsSniff.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<?php | ||
/** | ||
* PHPCompatibility, an external standard for PHP_CodeSniffer. | ||
* | ||
* @package PHPCompatibility | ||
* @copyright 2012-2022 PHPCompatibility Contributors | ||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3 | ||
* @link https://github.com/PHPCompatibility/PHPCompatibility | ||
*/ | ||
|
||
namespace PHPCompatibility\Sniffs\Classes; | ||
|
||
use PHPCompatibility\Sniff; | ||
use PHP_CodeSniffer\Files\File; | ||
use PHP_CodeSniffer\Util\Tokens; | ||
use PHPCSUtils\Utils\Scopes; | ||
|
||
/** | ||
* Using the "final" modifier for class constants is available since PHP 8.1. | ||
* | ||
* PHP version 8.1 | ||
* | ||
* @link https://wiki.php.net/rfc/final_class_const | ||
* @link https://www.php.net/manual/en/language.oop5.final.php#language.oop5.final.example.php81 | ||
* | ||
* @since 10.0.0 | ||
*/ | ||
class NewFinalClassConstantsSniff extends Sniff | ||
{ | ||
|
||
/** | ||
* Returns an array of tokens this test wants to listen for. | ||
* | ||
* @since 10.0.0 | ||
* | ||
* @return array | ||
*/ | ||
public function register() | ||
{ | ||
return [\T_CONST]; | ||
} | ||
|
||
/** | ||
* Processes this test, when one of its tokens is encountered. | ||
* | ||
* @since 10.0.0 | ||
* | ||
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. | ||
* @param int $stackPtr The position of the current token | ||
* in the stack passed in $tokens. | ||
* | ||
* @return void | ||
*/ | ||
public function process(File $phpcsFile, $stackPtr) | ||
{ | ||
if ($this->supportsBelow('8.0') === false) { | ||
return; | ||
} | ||
|
||
// Is this a class constant ? | ||
if (Scopes::isOOConstant($phpcsFile, $stackPtr) === false) { | ||
return; | ||
} | ||
|
||
$tokens = $phpcsFile->getTokens(); | ||
$skip = Tokens::$emptyTokens + Tokens::$scopeModifiers; | ||
$prevToken = $phpcsFile->findPrevious($skip, ($stackPtr - 1), null, true, null, true); | ||
|
||
// Is the previous token the final keyword ? | ||
if ($prevToken === false || $tokens[$prevToken]['code'] !== \T_FINAL) { | ||
return; | ||
} | ||
|
||
$phpcsFile->addError( | ||
'The final modifier for class constants is not supported in PHP 8.0 or earlier.', | ||
$stackPtr, | ||
'Found' | ||
); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
PHPCompatibility/Tests/Classes/NewFinalClassConstantsUnitTest.inc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
const NONCLASSCONST = 'foo'; | ||
|
||
class ConstDemo | ||
{ | ||
const MY_CONST = 1; | ||
|
||
// PHP 8.1+. | ||
final const FINAL_A = 2; | ||
final public const FINAL_PUBLIC_CONST_A = 3; | ||
public final const FINAL_PUBLIC_CONST_B = 4; | ||
final protected const FINAL_PROTECTED_CONST_A = 5; | ||
protected final const FINAL_PROTECTED_CONST_B = 6; | ||
|
||
// Fatal error as final with private is an oxymoron. | ||
final private const FINAL_PRIVATE_CONST_A = 7; | ||
private final const FINAL_PRIVATE_CONST_B = 8; | ||
} | ||
|
||
interface InterfaceDemo | ||
{ | ||
const MY_CONST = 1; | ||
|
||
// PHP 8.1+. | ||
final const FINAL_A = 2; | ||
final public /*comment*/ const FINAL_PUBLIC_CONST_A = 3; | ||
public final const FINAL_PUBLIC_CONST_B = 4; | ||
|
||
// Fatal error as interface constants must be public, but the check for which visibility indicator is used is outside the scope of this sniff. | ||
final /*comment*/ protected const FINAL_PROTECTED_CONST_A = 5; | ||
protected final const FINAL_PROTECTED_CONST_B = 6; | ||
|
||
// Fatal error as final with private is an oxymoron. | ||
final private const FINAL_PRIVATE_CONST_A = 7; | ||
private final const FINAL_PRIVATE_CONST_B = 8; | ||
} | ||
|
||
// Test anonymous classes. | ||
$a = new class | ||
{ | ||
const MY_CONST = 1; | ||
|
||
// PHP 8.1+. | ||
final const FINAL_A = 2; | ||
final public const FINAL_PUBLIC_CONST_A = 3; | ||
public final const FINAL_PUBLIC_CONST_B = 4; | ||
final protected const FINAL_PROTECTED_CONST_A = 5; | ||
protected final const FINAL_PROTECTED_CONST_B = 6; | ||
|
||
// Fatal error as final with private is an oxymoron. | ||
final private const FINAL_PRIVATE_CONST_A = 7; | ||
private final const FINAL_PRIVATE_CONST_B = 8; | ||
}; | ||
|
||
/* | ||
* Test against some false positives. | ||
* | ||
* Constants defined in the global namespace can not have the final modifier, | ||
* but this is outside the scope of this library. Would cause a parse error anyway. | ||
*/ | ||
final const GLOBAL_CONSTANT = 'not valid'; | ||
|
||
class NotAClassConstant { | ||
public function something() { | ||
final const GLOBAL_CONSTANT = 'not valid'; | ||
} | ||
} |
125 changes: 125 additions & 0 deletions
125
PHPCompatibility/Tests/Classes/NewFinalClassConstantsUnitTest.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
<?php | ||
/** | ||
* PHPCompatibility, an external standard for PHP_CodeSniffer. | ||
* | ||
* @package PHPCompatibility | ||
* @copyright 2012-2022 PHPCompatibility Contributors | ||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3 | ||
* @link https://github.com/PHPCompatibility/PHPCompatibility | ||
*/ | ||
|
||
namespace PHPCompatibility\Tests\Classes; | ||
|
||
use PHPCompatibility\Tests\BaseSniffTest; | ||
|
||
/** | ||
* Test the NewFinalClassConstants sniff. | ||
* | ||
* @group newFinalClassConstants | ||
* @group classes | ||
* | ||
* @covers \PHPCompatibility\Sniffs\Classes\NewFinalClassConstantsSniff | ||
* | ||
* @since 10.0.0 | ||
*/ | ||
class NewFinalClassConstantsUnitTest extends BaseSniffTest | ||
{ | ||
|
||
/** | ||
* Test that an error is thrown for class constants declared as final. | ||
* | ||
* @dataProvider dataFinalClassConstants | ||
* | ||
* @param int $line The line number. | ||
* | ||
* @return void | ||
*/ | ||
public function testFinalClassConstants($line) | ||
{ | ||
$file = $this->sniffFile(__FILE__, '8.0'); | ||
$this->assertError($file, $line, 'The final modifier for class constants is not supported in PHP 8.0 or earlier.'); | ||
} | ||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testFinalClassConstants() | ||
* | ||
* @return array | ||
*/ | ||
public function dataFinalClassConstants() | ||
{ | ||
return [ | ||
[10], | ||
[11], | ||
[12], | ||
[13], | ||
[14], | ||
[17], | ||
wimg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[18], | ||
|
||
[26], | ||
[27], | ||
[28], | ||
[31], | ||
[32], | ||
[35], | ||
[36], | ||
|
||
[45], | ||
[46], | ||
[47], | ||
[48], | ||
[49], | ||
[52], | ||
[53], | ||
]; | ||
} | ||
|
||
|
||
/** | ||
* Verify that there are no false positives for valid code/code errors outside the scope of this sniff. | ||
* | ||
* @dataProvider dataNoFalsePositives | ||
* | ||
* @param int $line The line number. | ||
* | ||
* @return void | ||
*/ | ||
public function testNoFalsePositives($line) | ||
{ | ||
$file = $this->sniffFile(__FILE__, '8.0'); | ||
$this->assertNoViolation($file, $line); | ||
} | ||
|
||
/** | ||
* Data provider. | ||
* | ||
* @see testNoFalsePositives() | ||
* | ||
* @return array | ||
*/ | ||
public function dataNoFalsePositives() | ||
{ | ||
return [ | ||
[3], | ||
[7], | ||
[23], | ||
[42], | ||
[62], | ||
[66], | ||
]; | ||
} | ||
|
||
|
||
/** | ||
* Verify no notices are thrown at all. | ||
* | ||
* @return void | ||
*/ | ||
public function testNoViolationsInFileOnValidVersion() | ||
{ | ||
$file = $this->sniffFile(__FILE__, '8.1'); | ||
$this->assertNoViolation($file); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
The HTML tag appears literally in markdown docs. I recommend avoiding markdown in code samples. Other than that, everything looks good on the docs side.
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.
The
<em>
markers are intended to highlight the "issue" in the HTML view.In the
Text
and theMarkDown
view, they are automatically removed when the report is generated.How did you generate the report to get them to show ?
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.
Just checked the source code of the generators which are included with PHPCS and the above is correct. Also tested with the docs for another sniff I was just working on.
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 the generator code I mean: https://github.com/squizlabs/PHP_CodeSniffer/blob/51335eb46b2b940b6c429643fe96f514d4a4e4a1/src/Generators/Markdown.php#L131-L141
If the code in the phpcs docs repo does not line up with that, it will need to be adjusted.