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

Breadcrumb

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

class YodaHelper

@internal

Hierarchy

  • class \SlevomatCodingStandard\Helpers\YodaHelper

Expanded class hierarchy of YodaHelper

2 files declare their use of YodaHelper
DisallowYodaComparisonSniff.php in vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowYodaComparisonSniff.php
RequireYodaComparisonSniff.php in vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireYodaComparisonSniff.php

File

vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/YodaHelper.php, line 68

Namespace

SlevomatCodingStandard\Helpers
View source
class YodaHelper {
    private const DYNAMISM_VARIABLE = 999;
    private const DYNAMISM_CONSTANT = 1;
    private const DYNAMISM_FUNCTION_CALL = 998;
    
    /**
     * @param array<int, array<string, array<int, int|string>|int|string>> $leftSideTokens
     * @param array<int, array<string, array<int, int|string>|int|string>> $rightSideTokens
     */
    public static function fix(File $phpcsFile, array $leftSideTokens, array $rightSideTokens) : void {
        $phpcsFile->fixer
            ->beginChangeset();
        self::replace($phpcsFile, $leftSideTokens, $rightSideTokens);
        self::replace($phpcsFile, $rightSideTokens, $leftSideTokens);
        $phpcsFile->fixer
            ->endChangeset();
    }
    
    /**
     * @param array<int, array<string, array<int, int|string>|int|string>> $tokens
     * @return array<int, array<string, array<int, int|string>|int|string>>
     */
    public static function getLeftSideTokens(array $tokens, int $comparisonTokenPointer) : array {
        $parenthesisDepth = 0;
        $shortArrayDepth = 0;
        $examinedTokenPointer = $comparisonTokenPointer;
        $sideTokens = [];
        $stopTokenCodes = self::getStopTokenCodes();
        while (true) {
            $examinedTokenPointer--;
            $examinedToken = $tokens[$examinedTokenPointer];
            
            /** @var string|int $examinedTokenCode */
            $examinedTokenCode = $examinedToken['code'];
            if ($parenthesisDepth === 0 && $shortArrayDepth === 0 && isset($stopTokenCodes[$examinedTokenCode])) {
                break;
            }
            if ($examinedTokenCode === T_CLOSE_SHORT_ARRAY) {
                $shortArrayDepth++;
            }
            elseif ($examinedTokenCode === T_OPEN_SHORT_ARRAY) {
                if ($shortArrayDepth === 0) {
                    break;
                }
                $shortArrayDepth--;
            }
            if ($examinedTokenCode === T_CLOSE_PARENTHESIS) {
                $parenthesisDepth++;
            }
            elseif ($examinedTokenCode === T_OPEN_PARENTHESIS) {
                if ($parenthesisDepth === 0) {
                    break;
                }
                $parenthesisDepth--;
            }
            $sideTokens[$examinedTokenPointer] = $examinedToken;
        }
        return self::trimWhitespaceTokens(array_reverse($sideTokens, true));
    }
    
    /**
     * @param array<int, array<string, array<int, int|string>|int|string>> $tokens
     * @return array<int, array<string, array<int, int|string>|int|string>>
     */
    public static function getRightSideTokens(array $tokens, int $comparisonTokenPointer) : array {
        $parenthesisDepth = 0;
        $shortArrayDepth = 0;
        $examinedTokenPointer = $comparisonTokenPointer;
        $sideTokens = [];
        $stopTokenCodes = self::getStopTokenCodes();
        while (true) {
            $examinedTokenPointer++;
            $examinedToken = $tokens[$examinedTokenPointer];
            
            /** @var string|int $examinedTokenCode */
            $examinedTokenCode = $examinedToken['code'];
            if ($parenthesisDepth === 0 && $shortArrayDepth === 0 && isset($stopTokenCodes[$examinedTokenCode])) {
                break;
            }
            if ($examinedTokenCode === T_OPEN_SHORT_ARRAY) {
                $shortArrayDepth++;
            }
            elseif ($examinedTokenCode === T_CLOSE_SHORT_ARRAY) {
                if ($shortArrayDepth === 0) {
                    break;
                }
                $shortArrayDepth--;
            }
            if ($examinedTokenCode === T_OPEN_PARENTHESIS) {
                $parenthesisDepth++;
            }
            elseif ($examinedTokenCode === T_CLOSE_PARENTHESIS) {
                if ($parenthesisDepth === 0) {
                    break;
                }
                $parenthesisDepth--;
            }
            $sideTokens[$examinedTokenPointer] = $examinedToken;
        }
        return self::trimWhitespaceTokens($sideTokens);
    }
    
    /**
     * @param array<int, array<string, array<int, int|string>|int|string>> $tokens
     * @param array<int, array<string, array<int, int|string>|int|string>> $sideTokens
     */
    public static function getDynamismForTokens(array $tokens, array $sideTokens) : ?int {
        $sideTokens = array_values(array_filter($sideTokens, static function (array $token) : bool {
            return !in_array($token['code'], [
                T_WHITESPACE,
                T_COMMENT,
                T_DOC_COMMENT,
                T_NS_SEPARATOR,
                T_PLUS,
                T_MINUS,
                T_INT_CAST,
                T_DOUBLE_CAST,
                T_STRING_CAST,
                T_ARRAY_CAST,
                T_OBJECT_CAST,
                T_BOOL_CAST,
                T_UNSET_CAST,
            ], true);
        }));
        $sideTokensCount = count($sideTokens);
        $dynamism = self::getTokenDynamism();
        if ($sideTokensCount > 0) {
            if ($sideTokens[0]['code'] === T_VARIABLE) {
                // Expression starts with a variable - wins over everything else
                return self::DYNAMISM_VARIABLE;
            }
            if ($sideTokens[$sideTokensCount - 1]['code'] === T_CLOSE_PARENTHESIS) {
                if (array_key_exists('parenthesis_owner', $sideTokens[$sideTokensCount - 1])) {
                    
                    /** @var int $parenthesisOwner */
                    $parenthesisOwner = $sideTokens[$sideTokensCount - 1]['parenthesis_owner'];
                    if ($tokens[$parenthesisOwner]['code'] === T_ARRAY) {
                        // Array
                        return $dynamism[T_ARRAY];
                    }
                }
                // Function or method call
                return self::DYNAMISM_FUNCTION_CALL;
            }
            if ($sideTokensCount === 1 && $sideTokens[0]['code'] === T_STRING) {
                // Constant
                return self::DYNAMISM_CONSTANT;
            }
        }
        if ($sideTokensCount > 2 && $sideTokens[$sideTokensCount - 2]['code'] === T_DOUBLE_COLON) {
            if ($sideTokens[$sideTokensCount - 1]['code'] === T_VARIABLE) {
                // Static property access
                return self::DYNAMISM_VARIABLE;
            }
            if ($sideTokens[$sideTokensCount - 1]['code'] === T_STRING) {
                // Class constant
                return self::DYNAMISM_CONSTANT;
            }
        }
        if (array_key_exists(0, $sideTokens)) {
            
            /** @var int $sideTokenCode */
            $sideTokenCode = $sideTokens[0]['code'];
            if (array_key_exists($sideTokenCode, $dynamism)) {
                return $dynamism[$sideTokenCode];
            }
        }
        return null;
    }
    
    /**
     * @param array<int, array<string, array<int, int|string>|int|string>> $tokens
     * @return array<int, array<string, array<int, int|string>|int|string>>
     */
    public static function trimWhitespaceTokens(array $tokens) : array {
        foreach ($tokens as $pointer => $token) {
            if ($token['code'] !== T_WHITESPACE) {
                break;
            }
            unset($tokens[$pointer]);
        }
        foreach (array_reverse($tokens, true) as $pointer => $token) {
            if ($token['code'] !== T_WHITESPACE) {
                break;
            }
            unset($tokens[$pointer]);
        }
        return $tokens;
    }
    
    /**
     * @param array<int, array<string, array<int, int|string>|int|string>> $oldTokens
     * @param array<int, array<string, array<int, int|string>|int|string>> $newTokens
     */
    private static function replace(File $phpcsFile, array $oldTokens, array $newTokens) : void {
        reset($oldTokens);
        
        /** @var int $firstOldPointer */
        $firstOldPointer = key($oldTokens);
        end($oldTokens);
        
        /** @var int $lastOldPointer */
        $lastOldPointer = key($oldTokens);
        $content = implode('', array_map(static function (array $token) : string {
            
            /** @var string $content */
            $content = $token['content'];
            return $content;
        }, $newTokens));
        FixerHelper::change($phpcsFile, $firstOldPointer, $lastOldPointer, $content);
    }
    
    /**
     * @return array<int|string, int>
     */
    private static function getTokenDynamism() : array {
        static $tokenDynamism;
        if ($tokenDynamism === null) {
            $tokenDynamism = [
                T_TRUE => 0,
                T_FALSE => 0,
                T_NULL => 0,
                T_DNUMBER => 0,
                T_LNUMBER => 0,
                T_OPEN_SHORT_ARRAY => 0,
                // Do not stack error messages when the old-style array syntax is used
T_ARRAY => 0,
                T_CONSTANT_ENCAPSED_STRING => 0,
                T_VARIABLE => self::DYNAMISM_VARIABLE,
                T_STRING => self::DYNAMISM_FUNCTION_CALL,
            ];
            $tokenDynamism += array_fill_keys(array_keys(Tokens::$castTokens), 3);
        }
        return $tokenDynamism;
    }
    
    /**
     * @return array<int|string, bool>
     */
    private static function getStopTokenCodes() : array {
        static $stopTokenCodes;
        if ($stopTokenCodes === null) {
            $stopTokenCodes = [
                T_BOOLEAN_AND => true,
                T_BOOLEAN_OR => true,
                T_SEMICOLON => true,
                T_OPEN_TAG => true,
                T_INLINE_THEN => true,
                T_INLINE_ELSE => true,
                T_LOGICAL_AND => true,
                T_LOGICAL_OR => true,
                T_LOGICAL_XOR => true,
                T_COALESCE => true,
                T_CASE => true,
                T_COLON => true,
                T_RETURN => true,
                T_COMMA => true,
                T_CLOSE_CURLY_BRACKET => true,
                T_MATCH_ARROW => true,
                T_FN_ARROW => true,
            ];
            $stopTokenCodes += array_fill_keys(array_keys(Tokens::$assignmentTokens), true);
            $stopTokenCodes += array_fill_keys(array_keys(Tokens::$commentTokens), true);
        }
        return $stopTokenCodes;
    }

}

Members

Title Sort descending Modifiers Object type Summary
YodaHelper::DYNAMISM_CONSTANT private constant
YodaHelper::DYNAMISM_FUNCTION_CALL private constant
YodaHelper::DYNAMISM_VARIABLE private constant
YodaHelper::fix public static function *
YodaHelper::getDynamismForTokens public static function *
YodaHelper::getLeftSideTokens public static function *
YodaHelper::getRightSideTokens public static function *
YodaHelper::getStopTokenCodes private static function *
YodaHelper::getTokenDynamism private static function *
YodaHelper::replace private static function *
YodaHelper::trimWhitespaceTokens public static function *
RSS feed
Powered by Drupal