function Helpers::getArrowFunctionOpenClose
* Find the opening and closing scope positions for an arrow function if the * given position is the start of the arrow function (the `fn` keyword * token). * * Returns null if the passed token is not an arrow function keyword. * * If the token is an arrow function keyword, the scope opener is returned as * the provided position. * *
Parameters
File $phpcsFile: * @param int $stackPtr * * @return ?array<string, int>
2 calls to Helpers::getArrowFunctionOpenClose()
- Helpers::getContainingArrowFunctionIndex in vendor/
sirbrillig/ phpcs-variable-analysis/ VariableAnalysis/ Lib/ Helpers.php - *
- Helpers::getScopeCloseForScopeOpen in vendor/
sirbrillig/ phpcs-variable-analysis/ VariableAnalysis/ Lib/ Helpers.php - *
File
-
vendor/
sirbrillig/ phpcs-variable-analysis/ VariableAnalysis/ Lib/ Helpers.php, line 747
Class
Namespace
VariableAnalysis\LibCode
public static function getArrowFunctionOpenClose(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();
if ($tokens[$stackPtr]['content'] !== 'fn') {
return null;
}
// Make sure next non-space token is an open parenthesis
$openParenIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true);
if (!is_int($openParenIndex) || $tokens[$openParenIndex]['code'] !== T_OPEN_PARENTHESIS) {
return null;
}
// Find the associated close parenthesis
$closeParenIndex = $tokens[$openParenIndex]['parenthesis_closer'];
// Make sure the next token is a fat arrow or a return type
$fatArrowIndex = $phpcsFile->findNext(Tokens::$emptyTokens, $closeParenIndex + 1, null, true);
if (!is_int($fatArrowIndex)) {
return null;
}
if ($tokens[$fatArrowIndex]['code'] !== T_DOUBLE_ARROW && $tokens[$fatArrowIndex]['type'] !== 'T_FN_ARROW' && $tokens[$fatArrowIndex]['code'] !== T_COLON) {
return null;
}
// Find the scope closer
$scopeCloserIndex = null;
$foundCurlyPairs = 0;
$foundArrayPairs = 0;
$foundParenPairs = 0;
$arrowBodyStart = $tokens[$stackPtr]['parenthesis_closer'] + 1;
$lastToken = self::getLastNonEmptyTokenIndexInFile($phpcsFile);
for ($index = $arrowBodyStart; $index < $lastToken; $index++) {
$token = $tokens[$index];
if (empty($token['code'])) {
$scopeCloserIndex = $index;
break;
}
$code = $token['code'];
// A semicolon is always a closer.
if ($code === T_SEMICOLON) {
$scopeCloserIndex = $index;
break;
}
// Track pair opening tokens.
if ($code === T_OPEN_CURLY_BRACKET) {
$foundCurlyPairs += 1;
continue;
}
if ($code === T_OPEN_SHORT_ARRAY || $code === T_OPEN_SQUARE_BRACKET) {
$foundArrayPairs += 1;
continue;
}
if ($code === T_OPEN_PARENTHESIS) {
$foundParenPairs += 1;
continue;
}
// A pair closing is only an arrow func closer if there was no matching opening token.
if ($code === T_CLOSE_CURLY_BRACKET) {
if ($foundCurlyPairs === 0) {
$scopeCloserIndex = $index;
break;
}
$foundCurlyPairs -= 1;
continue;
}
if ($code === T_CLOSE_SHORT_ARRAY || $code === T_CLOSE_SQUARE_BRACKET) {
if ($foundArrayPairs === 0) {
$scopeCloserIndex = $index;
break;
}
$foundArrayPairs -= 1;
continue;
}
if ($code === T_CLOSE_PARENTHESIS) {
if ($foundParenPairs === 0) {
$scopeCloserIndex = $index;
break;
}
$foundParenPairs -= 1;
continue;
}
// A comma is a closer only if we are not inside an opening token.
if ($code === T_COMMA) {
if (empty($foundArrayPairs) && empty($foundParenPairs) && empty($foundCurlyPairs)) {
$scopeCloserIndex = $index;
break;
}
continue;
}
}
if (!is_int($scopeCloserIndex)) {
return null;
}
return [
'scope_opener' => $stackPtr,
'scope_closer' => $scopeCloserIndex,
];
}