Skip to content

Proposal for supporting PHP 8.2+ Disjunctive Normal Form Types in the Tokenizer #387

Closed
@jrfnl

Description

@jrfnl

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 from T_ARRAY to T_STRING.
  • The true/false/null keywords when used in a type declaration may not be retokenized from T_STRING to T_TRUE/T_FALSE/T_NULL.
  • The & and | characters may not be retokenized to T_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 the array 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

Related issues

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions