Skip to content
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

PHP 8.4 | Add tokenization of asymmetric visibility #871

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

DanielEScherzer
Copy link
Contributor

@DanielEScherzer DanielEScherzer commented Mar 11, 2025

Description

Set up tokenization of asymmetric visibility modifiers:

  • Add tokens T_PUBLIC_SET, T_PROTECTED_SET, and T_PRIVATE_SET if not already defined
  • Consider them scope modifiers (PHP_CodeSniffer\Util\Tokens::$scopeModifiers)
  • Mark them as context sensitive (PHP_CodeSniffer\Util\Tokens::$contextSensitiveKeywords)
  • Store their known lengths (PHP_CodeSniffer\Tokenizers\PHP::$knownLengths)
  • Backfill tokenization for older versions of PHP

Suggested changelog entry

PHP 8.4 | Support tokenization of asymmetric visibility modifiers

Related issues/external references

Related to #851

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
    • This change is only breaking for integrators, not for external standards or end-users.
  • Documentation improvement

PR checklist

  • I have checked there is no other PR open for the same change.
  • I have read the Contribution Guidelines.
  • I grant the project the right to include and distribute the code under the BSD-3-Clause license (and I have the right to grant these rights).
  • I have added tests to cover my changes.
  • I have verified that the code complies with the projects coding standards.
  • [Required for new sniffs] I have added XML documentation for the sniff.

Tests need to pass on PHP 5 where `string` wasn't reserved yet
Copy link
Member

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DanielEScherzer Awesome work on this !

I have left a few comments and questions in-line, but generally speaking, this is looking great!

One additional question: how did you determine where in the (huge) PHP::tokenize() method, the polyfill should go ?
It is currently between the tokenization blocks for T_ENUM_CASE and PHP 8.0 namespaced names handling.
Is there a particular reason for that ?

&& in_array($token[0], [T_PUBLIC, T_PROTECTED, T_PRIVATE], true) === true
&& ($stackPtr + 3) < $numTokens
&& $tokens[($stackPtr + 1)] === '('
&& $tokens[($stackPtr + 2)][0] === T_STRING
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&& $tokens[($stackPtr + 2)][0] === T_STRING
&& is_array($tokens[($stackPtr + 2)]) === true
&& $tokens[($stackPtr + 2)][0] === T_STRING

Comment on lines +745 to +747
T_PRIVATE_SET => T_PRIVATE_SET,
T_PROTECTED => T_PROTECTED,
T_PROTECTED_SET => T_PROTECTED_SET,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is correct... Should these "keywords" ever be changed into T_STRING depending on their context.... ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is missing some tests to safeguard that invalid code is not affected by this polyfill.

Some suggestions, but feel free to get creative:

// Not valid as asym visibility in PHP 8.4.
public(unset) string $pubx;
public ( set ) string $pubx;
protected/*comment*/ ( set ) string $pubx;
Private{set} string $pubx;
public() string $pubx;
function public(Set $setter) {}

// Live coding test. Needs to be in a file of its own or at the end of the file without a new line after it (and this should be annotated as such to prevent someone adding that new line).
public(set

T_PROTECTED => T_PROTECTED,
T_PUBLIC_SET => T_PUBLIC_SET,
T_PROTECTED_SET => T_PROTECTED_SET,
T_PRIVATE_SET => T_PRIVATE_SET,
];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you done any tests how this change will affect pre-existing sniffs which use this token array ?

And if it affects pre-existing sniffs, should those be updated in the same PR to not leave those sniffs in a broken state ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants