Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. Helpers.php

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

Helpers

Namespace

VariableAnalysis\Lib

Code

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,
    ];
}

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal