Skip to content

Commit

Permalink
PHP 8.3 | PSR12/ClassInstantiation: allow for readonly anonymous classes
Browse files Browse the repository at this point in the history
The sniff is supposed to ignore anonymous class instantiations completely as otherwise it could create a conflict between this sniff and the PSR12 sniff checking anonymous class declarations.

As things were, however, the sniff would add parentheses after the `new` keyword or after an attribute if an anonymous class was declared as `readonly`, as allowed since PHP 8.3.

Fixed now.

Includes minor simplification - the sniff would previously _jump over_ attributes attached to anonymous classes to get to the `class` keyword only to bow out later for anonymous classes anyway.
Now, the sniff will bow out straight away when either an attribute, the `readonly` keyword or the `class` keyword for an anonymous class declaration is encountered.

As `readonly` cannot be used as class name and attributes cannot be attached to (non-anonymous) class instantiations, this should maintain the previous behaviour, while also allowing for PHP 8.3 readonly anonymous classes and it should yield a very small performance benefit as well.

Includes unit tests.
  • Loading branch information
jrfnl committed Feb 2, 2024
1 parent dc22022 commit 8c38d91
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 9 deletions.
15 changes: 6 additions & 9 deletions src/Standards/PSR12/Sniffs/Classes/ClassInstantiationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ public function process(File $phpcsFile, $stackPtr)
continue;
}

// Skip over potential attributes for anonymous classes.
// Bow out when this is an anonymous class.
// Anonymous classes are the only situation which would allow for an attribute
// or for the readonly keyword between "new" and the class "name".
if ($tokens[$i]['code'] === T_ATTRIBUTE
&& isset($tokens[$i]['attribute_closer']) === true
|| $tokens[$i]['code'] === T_READONLY
|| $tokens[$i]['code'] === T_ANON_CLASS
) {
$i = $tokens[$i]['attribute_closer'];
continue;
return;
}

if ($tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET
Expand All @@ -87,11 +89,6 @@ public function process(File $phpcsFile, $stackPtr)
return;
}

if ($tokens[$classNameEnd]['code'] === T_ANON_CLASS) {
// Ignore anon classes.
return;
}

if ($tokens[$classNameEnd]['code'] === T_OPEN_PARENTHESIS) {
// Using parenthesis.
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ $anonWithAttribute = new #[SomeAttribute('summary')] class {

$foo = new parent();
$foo = new parent;

// PHP 8.3: safeguard that the sniff ignores anonymous classes, even when declared as readonly.
$anon = new readonly class {};
$anon = new #[MyAttribute] readonly class {};
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ $anonWithAttribute = new #[SomeAttribute('summary')] class {

$foo = new parent();
$foo = new parent();

// PHP 8.3: safeguard that the sniff ignores anonymous classes, even when declared as readonly.
$anon = new readonly class {};
$anon = new #[MyAttribute] readonly class {};

0 comments on commit 8c38d91

Please sign in to comment.