Description
The problem
PHP 8.2 introduced Disjunctive Normal Form Types, which now adds parentheses to the tokens allowed within type declarations.
This is currently not yet supported by PHP_CodeSniffer and the PHP_CodeSniffer\Tokenizers\PHP
class will not always handle tokens within DNF types correctly, which can lead to false positives/false negatives being reported for sniffs and incorrect fixes being made.
Typical issues in the Tokenizer:
- The
array
keyword when used in a type declaration may not be retokenized fromT_ARRAY
toT_STRING
. - The
true
/false
/null
keywords when used in a type declaration may not be retokenized fromT_STRING
toT_TRUE
/T_FALSE
/T_NULL
. - The
&
and|
characters may not be retokenized toT_TYPE_UNION
/T_TYPE_INTERSECTION
.
Typical resulting sniff issues:
- Sniffs handling arbitrary parentheses spacing may act on parentheses in DNF types.
- Sniffs listening for the
array
keyword may try to act on thearray
keyword when used in a DNF type. - Sniffs listening for bitwise and/or operators may act on the
&
and|
characters in DNF types. - etc
These issues also impact the functioning of the following PHPCS native helper functions and by extension all sniffs which use these methods:
File::getMethodParameters()
(parameter types)File::getMethodProperties()
(return types)File::getMemberProperties()
(property types)File::isReference()
Compounding the Problem
Aside from the above, standards may want to treat (spacing around) parentheses in DNF types differently from (spacing around) parentheses used in other places in a code base.
Proposed Solution
To support DNF types the PHP_CodeSniffer\Tokenizers\PHP
class will need significant updates.
When making these updates, I propose to include a change to retokenize the open and close parentheses when used in DNF types as T_TYPE_OPEN_PARENTHESIS
and T_TYPE_CLOSE_PARENTHESIS
respectively.
Having separate, PHPCS native tokens for the DNF parentheses will allow for sniff developers to decide on a case-by-case basis whether a sniff should or should not act on DNF parentheses.
This change also follows in the footsteps of the retokenization of the &
and |
tokens (when used in types) to T_TYPE_*
tokens.
As part of this change, the new T_TYPE_OPEN_PARENTHESIS
and T_TYPE_CLOSE_PARENTHESIS
tokens will need to be handled correctly by the PHP_CodeSniffer\Tokenizers\Tokenizer
class and tokens should get the parenthesis_opener
, parenthesis_closer
and nested_parenthesis
tokens, same as if the tokens were the "normal" T_OPEN_PARENTHESIS
and T_CLOSE_PARENTHESIS
tokens.
Open question
As PHP 8.2 has been out for a while, some external standards may have implemented work-arounds for the current state of things.
So, aside from opinions on the above proposal itself, I would also like to hear opinions on when this change should be made.
- Should this change go into the next PHPCS 3.x minor (once the PR has been prepared) ?
- Or should this change go into PHPCS 4.0 ? (expected in 3-4 months)
/cc @asispts @dingo-d @fredden @GaryJones @greg0ire @kukulich @michalbundyra @Ocramius @sirbrillig @stronk7 @weierophinney @wimg