-
-
Notifications
You must be signed in to change notification settings - Fork 193
Description
Bug description
SlevomatCodingStandard.ControlStructures.NewWithoutParentheses incorrectly removes
empty constructor parentheses from new ClassName() when the expression is immediately
chained with ->method(). The resulting code is a parse error in PHP 8.4 and earlier.
Versions
- slevomat/coding-standard:
8.27.1 - PHP:
8.4.4
Steps to reproduce
<?php
$date = new DateTime()->setTime(0, 0);Run phpcbf with SlevomatCodingStandard.ControlStructures.NewWithoutParentheses enabled.
Actual result
<?php
$date = new DateTime->setTime(0, 0);
Expected result
No change – the sniff should leave the code untouched.
Why this is a bug
PHP 8.4 added support for new Foo()->method() (chaining directly without outer
parentheses). However, new Foo->method() – without constructor () – is still
a parse error in PHP 8.4:
Parse error: syntax error, unexpected token "->", expecting ")" in ...
The sniff correctly detects that () contains no arguments, but does not check
what follows the closing ). When an object operator -> (or ::) follows, the
parentheses are not useless – they are required for the expression to be valid.
Root cause
In NewWithoutParenthesesSniff::process(), after confirming the parentheses are empty
(lines 81–84), there is no check for what token follows the closing ). A fix would be
to add before line 86:
$afterCloser = TokenHelper::findNextEffective(
$phpcsFile,
$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1,
);
if (in_array($tokens[$afterCloser]['code'], [T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR, T_DOUBLE_COLON], true)) {
return;
}
Workaround
<rule ref="SlevomatCodingStandard.ControlStructures.NewWithoutParentheses">
<exclude name="SlevomatCodingStandard.ControlStructures.NewWithoutParentheses.UselessParentheses"/>
</rule>