Skip to content

Commit

Permalink
Merge pull request #363 from PHPCSStandards/php-8.1/add-support-for-r…
Browse files Browse the repository at this point in the history
…eadonly-properties

PHP 8.1: add support for readonly properties
  • Loading branch information
jrfnl committed Oct 15, 2022
2 parents 7472c96 + 1c40a07 commit b847a95
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 4 deletions.
15 changes: 15 additions & 0 deletions PHPCSUtils/BackCompat/BCFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ public static function getDeclarationName(File $phpcsFile, $stackPtr)
* ```php
* 'property_visibility' => string, // The property visibility as declared.
* 'visibility_token' => integer, // The stack pointer to the visibility modifier token.
* 'property_readonly' => bool, // TRUE if the readonly keyword was found.
* 'readonly_token' => integer, // The stack pointer to the readonly modifier token.
* ```
*
* PHPCS cross-version compatible version of the `File::getMethodParameters()` method.
Expand Down Expand Up @@ -217,6 +219,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
$typeHintEndToken = false;
$nullableType = false;
$visibilityToken = null;
$readonlyToken = null;

for ($i = $paramStart; $i <= $closer; $i++) {
// Check to see if this token has a parenthesis or bracket opener. If it does
Expand Down Expand Up @@ -345,6 +348,11 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
$visibilityToken = $i;
}
break;
case T_READONLY:
if ($defaultStart === null) {
$readonlyToken = $i;
}
break;
case T_CLOSE_PARENTHESIS:
case T_COMMA:
// If it's null, then there must be no parameters for this
Expand Down Expand Up @@ -377,6 +385,12 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
if ($visibilityToken !== null) {
$vars[$paramCount]['property_visibility'] = $tokens[$visibilityToken]['content'];
$vars[$paramCount]['visibility_token'] = $visibilityToken;
$vars[$paramCount]['property_readonly'] = false;
}

if ($readonlyToken !== null) {
$vars[$paramCount]['property_readonly'] = true;
$vars[$paramCount]['readonly_token'] = $readonlyToken;
}

if ($tokens[$i]['code'] === T_COMMA) {
Expand All @@ -400,6 +414,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
$typeHintEndToken = false;
$nullableType = false;
$visibilityToken = null;
$readonlyToken = null;

++$paramCount;
break;
Expand Down
2 changes: 2 additions & 0 deletions PHPCSUtils/Tokens/Collections.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,7 @@ class Collections
* DEPRECATED: Modifier keywords which can be used for a property declaration.
*
* @since 1.0.0-alpha1
* @since 1.0.0-alpha4 Added the T_READONLY token for PHP 8.1 readonly properties.
*
* @deprecated 1.0.0-alpha4 Use the {@see Collections::propertyModifierKeywords()} method instead.
*
Expand All @@ -514,6 +515,7 @@ class Collections
\T_PROTECTED => \T_PROTECTED,
\T_STATIC => \T_STATIC,
\T_VAR => \T_VAR,
\T_READONLY => \T_READONLY,
];

/**
Expand Down
15 changes: 15 additions & 0 deletions PHPCSUtils/Utils/FunctionDeclarations.php
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ public static function getProperties(File $phpcsFile, $stackPtr)
* ```php
* 'property_visibility' => string, // The property visibility as declared.
* 'visibility_token' => integer, // The stack pointer to the visibility modifier token.
* 'property_readonly' => bool, // TRUE if the readonly keyword was found.
* 'readonly_token' => integer, // The stack pointer to the readonly modifier token.
* ```
*
* Main differences with the PHPCS version:
Expand All @@ -361,6 +363,7 @@ public static function getProperties(File $phpcsFile, $stackPtr)
* @since 1.0.0-alpha4 Added support for PHP 8.0 constructor property promotion.
* @since 1.0.0-alpha4 Added support for PHP 8.0 identifier name tokenization.
* @since 1.0.0-alpha4 Added support for PHP 8.0 parameter attributes.
* @since 1.0.0-alpha4 Added support for PHP 8.1 readonly keyword for constructor property promotion.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position in the stack of the function token
Expand Down Expand Up @@ -426,6 +429,7 @@ public static function getParameters(File $phpcsFile, $stackPtr)
$typeHintEndToken = false;
$nullableType = false;
$visibilityToken = null;
$readonlyToken = null;

for ($i = $paramStart; $i <= $closer; $i++) {
if (isset(Collections::parameterTypeTokens()[$tokens[$i]['code']]) === true
Expand Down Expand Up @@ -475,6 +479,10 @@ public static function getParameters(File $phpcsFile, $stackPtr)
$visibilityToken = $i;
break;

case \T_READONLY:
$readonlyToken = $i;
break;

case \T_CLOSE_PARENTHESIS:
case \T_COMMA:
// If it's null, then there must be no parameters for this
Expand Down Expand Up @@ -511,6 +519,12 @@ public static function getParameters(File $phpcsFile, $stackPtr)
if ($visibilityToken !== null) {
$vars[$paramCount]['property_visibility'] = $tokens[$visibilityToken]['content'];
$vars[$paramCount]['visibility_token'] = $visibilityToken;
$vars[$paramCount]['property_readonly'] = false;
}

if ($readonlyToken !== null) {
$vars[$paramCount]['property_readonly'] = true;
$vars[$paramCount]['readonly_token'] = $readonlyToken;
}

if ($tokens[$i]['code'] === \T_COMMA) {
Expand All @@ -534,6 +548,7 @@ public static function getParameters(File $phpcsFile, $stackPtr)
$typeHintEndToken = false;
$nullableType = false;
$visibilityToken = null;
$readonlyToken = null;

++$paramCount;
break;
Expand Down
7 changes: 7 additions & 0 deletions PHPCSUtils/Utils/Variables.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class Variables
* @since 1.0.0
* @since 1.0.0-alpha4 Added support for PHP 8.0 union types.
* @since 1.0.0-alpha4 No longer gets confused by PHP 8.0 property attributes.
* @since 1.0.0-alpha4 Added support for PHP 8.1 readonly properties.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position in the stack of the `T_VARIABLE` token
Expand All @@ -101,6 +102,7 @@ class Variables
* 'scope' => string, // Public, private, or protected.
* 'scope_specified' => boolean, // TRUE if the scope was explicitly specified.
* 'is_static' => boolean, // TRUE if the static keyword was found.
* 'is_readonly' => boolean, // TRUE if the readonly keyword was found.
* 'type' => string, // The type of the var (empty if no type specified).
* 'type_token' => integer, // The stack pointer to the start of the type
* // or FALSE if there is no type.
Expand Down Expand Up @@ -133,6 +135,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr)
$scope = 'public';
$scopeSpecified = false;
$isStatic = false;
$isReadonly = false;

$startOfStatement = $phpcsFile->findPrevious(
[
Expand Down Expand Up @@ -165,6 +168,9 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr)
case \T_STATIC:
$isStatic = true;
break;
case \T_READONLY:
$isReadonly = true;
break;
}
}

Expand Down Expand Up @@ -205,6 +211,7 @@ public static function getMemberProperties(File $phpcsFile, $stackPtr)
'scope' => $scope,
'scope_specified' => $scopeSpecified,
'is_static' => $isStatic,
'is_readonly' => $isReadonly,
'type' => $type,
'type_token' => $typeToken,
'type_end_token' => $typeEndToken,
Expand Down
25 changes: 25 additions & 0 deletions Tests/BackCompat/BCFile/GetMemberPropertiesTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,31 @@ $anon = class() {
/* testPHP8DuplicateTypeInUnionWhitespaceAndComment */
// Intentional fatal error - duplicate types are not allowed in union types, but that's not the concern of the method.
public int |string| /*comment*/ INT $duplicateTypeInUnion;

/* testPHP81Readonly */
public readonly int $readonly;

/* testPHP81ReadonlyWithNullableType */
public readonly ?array $readonlyWithNullableType;

/* testPHP81ReadonlyWithUnionType */
public readonly string|int $readonlyWithUnionType;

/* testPHP81ReadonlyWithUnionTypeWithNull */
protected ReadOnly string|null $readonlyWithUnionTypeWithNull;

/* testPHP81OnlyReadonlyWithUnionType */
readonly string|int $onlyReadonly;

/* testPHP81OnlyReadonlyWithUnionTypeMultiple */
readonly \InterfaceA|\Sub\InterfaceB|false
$onlyReadonly;

/* testPHP81ReadonlyAndStatic */
readonly private static ?string $readonlyAndStatic;

/* testPHP81ReadonlyMixedCase */
public ReadONLY static $readonlyMixedCase;
};

$anon = class {
Expand Down
Loading

0 comments on commit b847a95

Please sign in to comment.