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.0: add support for match expressions #356

Merged
merged 2 commits into from
Oct 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions PHPCSUtils/Tokens/Collections.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ class Collections
* DEPRECATED: Control structure tokens.
*
* @since 1.0.0-alpha2
* @since 1.0.0-alpha4 Added the T_MATCH token for PHP 8.0 match expressions.
*
* @deprecated 1.0.0-alpha4 Use the {@see Collections::controlStructureTokens()} method instead.
*
Expand All @@ -217,6 +218,7 @@ class Collections
\T_DO => \T_DO,
\T_WHILE => \T_WHILE,
\T_DECLARE => \T_DECLARE,
\T_MATCH => \T_MATCH,
];

/**
Expand Down
5 changes: 4 additions & 1 deletion PHPCSUtils/Utils/Arrays.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Arrays

// Inline function and control structures to skip over.
\T_FN => \T_FN,
\T_MATCH => \T_MATCH,
];

/**
Expand Down Expand Up @@ -295,6 +296,7 @@ public static function getOpenClose(File $phpcsFile, $stackPtr, $isShortArray =
*
* @since 1.0.0
* @since 1.0.0-alpha2 Now allows for arrow functions in arrays.
* @since 1.0.0-alpha4 Now allows for match expressions in arrays.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being examined.
* @param int $start Stack pointer to the start of the array item.
Expand Down Expand Up @@ -344,7 +346,8 @@ public static function getDoubleArrowPtr(File $phpcsFile, $start, $end)

// Skip over closed scopes which may contain foreach structures or generators.
if ((isset(Collections::closedScopes()[$tokens[$doubleArrow]['code']]) === true
|| $tokens[$doubleArrow]['code'] === \T_FN)
|| $tokens[$doubleArrow]['code'] === \T_FN
|| $tokens[$doubleArrow]['code'] === \T_MATCH)
&& isset($tokens[$doubleArrow]['scope_closer']) === true
) {
$doubleArrow = $tokens[$doubleArrow]['scope_closer'];
Expand Down
1 change: 1 addition & 0 deletions PHPCSUtils/Utils/ControlStructures.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class ControlStructures
* regarded as empty.
*
* @since 1.0.0
* @since 1.0.0-alpha4 Added support for PHP 8.0 match control structures.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the token we are checking.
Expand Down
18 changes: 18 additions & 0 deletions Tests/Utils/Arrays/GetDoubleArrowPtrTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ $array = [
/* testDoubleArrowTokenizedAsTstring-PHPCS2865 */
$obj->fn => 'value',

/* testNoArrowValueMatchExpr */
match($a) {
FOO => BAR,
default => [0 => BAZ],
},

/* testArrowValueMatchExpr */
'key' => match($a) {
[0 => 10] => BAR,
default => BAZ,
},

/* testArrowKeyMatchExpr */
match($a) {
FOO => BAR,
default => [0 => 10],
} => 'value',

/* testEmptyArrayItem */
// Intentional parse error.
,
Expand Down
15 changes: 15 additions & 0 deletions Tests/Utils/Arrays/GetDoubleArrowPtrTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,21 @@ public function dataGetDoubleArrowPtr()
'testMarker' => '/* testDoubleArrowTokenizedAsTstring-PHPCS2865 */',
'expected' => 10,
],

// Safeguard that PHP 8.0 match expressions are handled correctly.
'test-no-arrow-value-match-expression' => [
'testMarker' => '/* testNoArrowValueMatchExpr */',
'expected' => false,
],
'test-double-arrow-value-match-expression' => [
'testMarker' => '/* testArrowValueMatchExpr */',
'expected' => 8,
],
'test-double-arrow-key-match-expression' => [
'testMarker' => '/* testArrowKeyMatchExpr */',
'expected' => 38,
],

'test-empty-array-item' => [
'testMarker' => '/* testEmptyArrayItem */',
'expected' => false,
Expand Down
22 changes: 22 additions & 0 deletions Tests/Utils/ControlStructures/HasBodyTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,28 @@ do
echo $i;
while (++$i <= 10);


/*
* PHP 8.0 match expressions.
*/

/* testMatchEmptyBody */
// Intentional fatal error, "unhandled match case", but not the concern of this method.
$match = match($a) {};

/* testMatchEmptyBodyWithComment */
// Intentional fatal error, "unhandled match case", but not the concern of this method.
$match = match($a) {
// Deliberately empty.
};

/* testMatchWithCode */
$match = match ($a) {
0 => 'Foo',
1 => 'Bar',
2 => 'Baz',
};

// Live coding.
// Intentional parse error. This test has to be the last in the file.
if ($a) {
Expand Down
23 changes: 23 additions & 0 deletions Tests/Utils/ControlStructures/HasBodyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,29 @@ public function dataHasBody()
'hasBody' => true,
'hasNonEmptyBody' => true,
],

/*
* Match without body cannot be tested as, in that case, `match` will tokenize as `T_STRING`.
* Without body (`match();`), match will either yield a parse error
* or be interpreted as a function call (`\match();` or `self::match()` etc).
*/

'match-empty-body' => [
'testMarker' => '/* testMatchEmptyBody */',
'hasBody' => true,
'hasNonEmptyBody' => false,
],
'match-empty-body-comment-only' => [
'testMarker' => '/* testMatchEmptyBodyWithComment */',
'hasBody' => true,
'hasNonEmptyBody' => false,
],
'match-with-code' => [
'testMarker' => '/* testMatchWithCode */',
'hasBody' => true,
'hasNonEmptyBody' => true,
],

'else-live-coding' => [
'testMarker' => '/* testElseLiveCoding */',
'hasBody' => true,
Expand Down