/** * Processes the tokens within the scope. * * @param PHP_CodeSniffer_File $phpcsFile The file being processed. * @param int $stackPtr The position where this token was * found. * @param int $currScope The position of the current scope. * * @return void */ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) { $methodName = $phpcsFile->getDeclarationName($stackPtr); if ($methodName === null) { // Ignore closures. return; } // Ignore magic methods. if (preg_match('|^__|', $methodName) !== 0) { $magicPart = strtolower(substr($methodName, 2)); if (isset($this->magicMethods[$magicPart]) === true || isset($this->methodsDoubleUnderscore[$magicPart]) === true) { return; } } $testName = ltrim($methodName, '_'); if ($testName !== '' && Common::isCamelCaps($testName, false, true, false) === false) { $error = 'Method name "%s" is not in camel caps format'; $className = $phpcsFile->getDeclarationName($currScope); $errorData = array($className . '::' . $methodName); $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); $phpcsFile->recordMetric($stackPtr, 'CamelCase method name', 'no'); } else { $phpcsFile->recordMetric($stackPtr, 'CamelCase method name', 'yes'); } }
/** * Processes the function tokens within the class. * * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. * @param int $stackPtr The position where the token was found. * @param int $currScope The current scope opener token. * * @return void */ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) { $tokens = $phpcsFile->getTokens(); $methodName = $phpcsFile->getDeclarationName($stackPtr); if ($methodName === null) { // Ignore closures. return; } if ($phpcsFile->hasCondition($stackPtr, T_FUNCTION) === true) { // Ignore nested functions. return; } $modifier = null; for ($i = $stackPtr - 1; $i > 0; $i--) { if ($tokens[$i]['line'] < $tokens[$stackPtr]['line']) { break; } else { if (isset(Tokens::$scopeModifiers[$tokens[$i]['code']]) === true) { $modifier = $i; break; } } } if ($modifier === null) { $error = 'Visibility must be declared on method "%s"'; $data = array($methodName); $phpcsFile->addError($error, $stackPtr, 'Missing', $data); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if (empty($tokens[$stackPtr]['conditions']) === true) { $functionName = $phpcsFile->getDeclarationName($stackPtr); if ($functionName === null) { return; } // Special exception for __autoload as it needs to be global. if ($functionName !== '__autoload') { $error = 'Consider putting global function "%s" in a static class'; $data = array($functionName); $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); } } }
/** * Processes the tokens outside the scope. * * @param PHP_CodeSniffer_File $phpcsFile The file being processed. * @param int $stackPtr The position where this token was * found. * * @return void */ protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) { $functionName = $phpcsFile->getDeclarationName($stackPtr); if ($functionName === null) { return; } $errorData = array($functionName); // Does this function claim to be magical? if (preg_match('|^__|', $functionName) !== 0) { $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; $phpcsFile->addError($error, $stackPtr, 'DoubleUnderscore', $errorData); return; } if (Common::isCamelCaps($functionName, false, true, false) === false) { $error = 'Function name "%s" is not in camel caps format'; $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); } }
/** * Processes this test when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The current file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * @param int $currScope A pointer to the start of the scope. * * @return void */ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) { $className = $phpcsFile->getDeclarationName($currScope); if ($className !== $this->currentClass) { $this->loadFunctionNamesInScope($phpcsFile, $currScope); $this->currentClass = $className; } $methodName = $phpcsFile->getDeclarationName($stackPtr); if (strcasecmp($methodName, $className) === 0) { if (in_array('__construct', $this->functionList) === false) { $error = 'PHP4 style constructors are not allowed; use "__construct()" instead'; $phpcsFile->addError($error, $stackPtr, 'OldStyle'); } } else { if (strcasecmp($methodName, '__construct') !== 0) { // Not a constructor. return; } } $tokens = $phpcsFile->getTokens(); $parentClassName = $phpcsFile->findExtendedClassName($currScope); if ($parentClassName === false) { return; } // Stop if the constructor doesn't have a body, like when it is abstract. if (isset($tokens[$stackPtr]['scope_closer']) === false) { return; } $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; $startIndex = $stackPtr; while (($doubleColonIndex = $phpcsFile->findNext(T_DOUBLE_COLON, $startIndex, $endFunctionIndex)) !== false) { if ($tokens[$doubleColonIndex + 1]['code'] === T_STRING && $tokens[$doubleColonIndex + 1]['content'] === $parentClassName) { $error = 'PHP4 style calls to parent constructors are not allowed; use "parent::__construct()" instead'; $phpcsFile->addError($error, $doubleColonIndex + 1, 'OldStyleCall'); } $startIndex = $doubleColonIndex + 1; } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the * stack passed in $tokens.. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['code'] === T_FUNCTION) { $methodProps = $phpcsFile->getMethodProperties($stackPtr); // Abstract methods do not require a closing comment. if ($methodProps['is_abstract'] === true) { return; } // Closures do not require a closing comment. if ($methodProps['is_closure'] === true) { return; } // If this function is in an interface then we don't require // a closing comment. if ($phpcsFile->hasCondition($stackPtr, T_INTERFACE) === true) { return; } if (isset($tokens[$stackPtr]['scope_closer']) === false) { $error = 'Possible parse error: non-abstract method defined as abstract'; $phpcsFile->addWarning($error, $stackPtr, 'Abstract'); return; } $decName = $phpcsFile->getDeclarationName($stackPtr); $comment = '//end ' . $decName . '()'; } else { if ($tokens[$stackPtr]['code'] === T_CLASS) { $comment = '//end class'; } else { $comment = '//end interface'; } } //end if if (isset($tokens[$stackPtr]['scope_closer']) === false) { $error = 'Possible parse error: %s missing opening or closing brace'; $data = array($tokens[$stackPtr]['content']); $phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data); return; } $closingBracket = $tokens[$stackPtr]['scope_closer']; if ($closingBracket === null) { // Possible inline structure. Other tests will handle it. return; } $error = 'Expected ' . $comment; if (isset($tokens[$closingBracket + 1]) === false || $tokens[$closingBracket + 1]['code'] !== T_COMMENT) { $next = $phpcsFile->findNext(T_WHITESPACE, $closingBracket + 1, null, true); if (rtrim($tokens[$next]['content']) === $comment) { // The comment isn't really missing; it is just in the wrong place. $fix = $phpcsFile->addFixableError($error . ' directly after closing brace', $closingBracket, 'Misplaced'); if ($fix === true) { $phpcsFile->fixer->beginChangeset(); for ($i = $closingBracket + 1; $i < $next; $i++) { $phpcsFile->fixer->replaceToken($i, ''); } // Just in case, because indentation fixes can add indents onto // these comments and cause us to be unable to fix them. $phpcsFile->fixer->replaceToken($next, $comment . $phpcsFile->eolChar); $phpcsFile->fixer->endChangeset(); } } else { $fix = $phpcsFile->addFixableError($error, $closingBracket, 'Missing'); if ($fix === true) { $phpcsFile->fixer->replaceToken($closingBracket, '}' . $comment . $phpcsFile->eolChar); } } return; } //end if if (rtrim($tokens[$closingBracket + 1]['content']) !== $comment) { $fix = $phpcsFile->addFixableError($error, $closingBracket, 'Incorrect'); if ($fix === true) { $phpcsFile->fixer->replaceToken($closingBracket + 1, $comment . $phpcsFile->eolChar); } return; } }
/** * Processes the tokens outside the scope. * * @param PHP_CodeSniffer_File $phpcsFile The file being processed. * @param int $stackPtr The position where this token was * found. * * @return void */ protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) { $functionName = $phpcsFile->getDeclarationName($stackPtr); if ($functionName === null) { // Ignore closures. return; } if (ltrim($functionName, '_') === '') { // Ignore special functions. return; } $errorData = array($functionName); // Is this a magic function. i.e., it is prefixed with "__". if (preg_match('|^__|', $functionName) !== 0) { $magicPart = strtolower(substr($functionName, 2)); if (isset($this->magicFunctions[$magicPart]) === false) { $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; $phpcsFile->addError($error, $stackPtr, 'FunctionDoubleUnderscore', $errorData); } return; } // Function names can be in two parts; the package name and // the function name. $packagePart = ''; $camelCapsPart = ''; $underscorePos = strrpos($functionName, '_'); if ($underscorePos === false) { $camelCapsPart = $functionName; } else { $packagePart = substr($functionName, 0, $underscorePos); $camelCapsPart = substr($functionName, $underscorePos + 1); // We don't care about _'s on the front. $packagePart = ltrim($packagePart, '_'); } // If it has a package part, make sure the first letter is a capital. if ($packagePart !== '') { if ($functionName[0] === '_') { $error = 'Function name "%s" is invalid; only private methods should be prefixed with an underscore'; $phpcsFile->addError($error, $stackPtr, 'FunctionUnderscore', $errorData); return; } if ($functionName[0] !== strtoupper($functionName[0])) { $error = 'Function name "%s" is prefixed with a package name but does not begin with a capital letter'; $phpcsFile->addError($error, $stackPtr, 'FunctionNoCapital', $errorData); return; } } // If it doesn't have a camel caps part, it's not valid. if (trim($camelCapsPart) === '') { $error = 'Function name "%s" is not valid; name appears incomplete'; $phpcsFile->addError($error, $stackPtr, 'FunctionInvalid', $errorData); return; } $validName = true; $newPackagePart = $packagePart; $newCamelCapsPart = $camelCapsPart; // Every function must have a camel caps part, so check that first. if (Common::isCamelCaps($camelCapsPart, false, true, false) === false) { $validName = false; $newCamelCapsPart = strtolower($camelCapsPart[0]) . substr($camelCapsPart, 1); } if ($packagePart !== '') { // Check that each new word starts with a capital. $nameBits = explode('_', $packagePart); foreach ($nameBits as $bit) { if ($bit[0] !== strtoupper($bit[0])) { $newPackagePart = ''; foreach ($nameBits as $bit) { $newPackagePart .= strtoupper($bit[0]) . substr($bit, 1) . '_'; } $validName = false; break; } } } if ($validName === false) { $newName = rtrim($newPackagePart, '_') . '_' . $newCamelCapsPart; if ($newPackagePart === '') { $newName = $newCamelCapsPart; } else { $newName = rtrim($newPackagePart, '_') . '_' . $newCamelCapsPart; } $error = 'Function name "%s" is invalid; consider "%s" instead'; $data = $errorData; $data[] = $newName; $phpcsFile->addError($error, $stackPtr, 'FunctionNameInvalid', $data); } }
/** * Processes the tokens outside the scope. * * @param PHP_CodeSniffer_File $phpcsFile The file being processed. * @param int $stackPtr The position where this token was * found. * * @return void */ protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) { $functionName = $phpcsFile->getDeclarationName($stackPtr); if ($functionName === null) { // Ignore closures. return; } $errorData = array($functionName); // Is this a magic function. i.e., it is prefixed with "__". if (preg_match('|^__|', $functionName) !== 0) { $magicPart = strtolower(substr($functionName, 2)); if (isset($this->magicFunctions[$magicPart]) === false) { $error = 'Function name "%s" is invalid; only PHP magic methods should be prefixed with a double underscore'; $phpcsFile->addError($error, $stackPtr, 'FunctionDoubleUnderscore', $errorData); } return; } // Ignore first underscore in functions prefixed with "_". $functionName = ltrim($functionName, '_'); if (Common::isCamelCaps($functionName, false, true, $this->strict) === false) { $error = 'Function name "%s" is not in camel caps format'; $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $errorData); $phpcsFile->recordMetric($stackPtr, 'CamelCase function name', 'no'); } else { $phpcsFile->recordMetric($stackPtr, 'CamelCase method name', 'yes'); } }
/** * Process the return comment of this function comment. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * @param int $commentStart The position in the stack where the comment started. * * @return void */ protected function processReturn(File $phpcsFile, $stackPtr, $commentStart) { $tokens = $phpcsFile->getTokens(); // Skip constructor and destructor. $methodName = $phpcsFile->getDeclarationName($stackPtr); $isSpecialMethod = $methodName === '__construct' || $methodName === '__destruct'; $return = null; foreach ($tokens[$commentStart]['comment_tags'] as $tag) { if ($tokens[$tag]['content'] === '@return') { if ($return !== null) { $error = 'Only 1 @return tag is allowed in a function comment'; $phpcsFile->addError($error, $tag, 'DuplicateReturn'); return; } $return = $tag; } } if ($isSpecialMethod === true) { return; } if ($return !== null) { $content = $tokens[$return + 2]['content']; if (empty($content) === true || $tokens[$return + 2]['code'] !== T_DOC_COMMENT_STRING) { $error = 'Return type missing for @return tag in function comment'; $phpcsFile->addError($error, $return, 'MissingReturnType'); } } else { $error = 'Missing @return tag in function comment'; $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn'); } //end if }
/** * Process the return comment of this function comment. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * @param int $commentStart The position in the stack where the comment started. * * @return void */ protected function processReturn(File $phpcsFile, $stackPtr, $commentStart) { $tokens = $phpcsFile->getTokens(); // Skip constructor and destructor. $methodName = $phpcsFile->getDeclarationName($stackPtr); $isSpecialMethod = $methodName === '__construct' || $methodName === '__destruct'; $return = null; foreach ($tokens[$commentStart]['comment_tags'] as $tag) { if ($tokens[$tag]['content'] === '@return') { if ($return !== null) { $error = 'Only 1 @return tag is allowed in a function comment'; $phpcsFile->addError($error, $tag, 'DuplicateReturn'); return; } $return = $tag; } } if ($isSpecialMethod === true) { return; } if ($return !== null) { $content = $tokens[$return + 2]['content']; if (empty($content) === true || $tokens[$return + 2]['code'] !== T_DOC_COMMENT_STRING) { $error = 'Return type missing for @return tag in function comment'; $phpcsFile->addError($error, $return, 'MissingReturnType'); } else { // Check return type (can be multiple, separated by '|'). $typeNames = explode('|', $content); $suggestedNames = array(); foreach ($typeNames as $i => $typeName) { $suggestedName = Common::suggestType($typeName); if (in_array($suggestedName, $suggestedNames) === false) { $suggestedNames[] = $suggestedName; } } $suggestedType = implode('|', $suggestedNames); if ($content !== $suggestedType) { $error = 'Expected "%s" but found "%s" for function return type'; $data = array($suggestedType, $content); $fix = $phpcsFile->addFixableError($error, $return, 'InvalidReturn', $data); if ($fix === true) { $phpcsFile->fixer->replaceToken($return + 2, $suggestedType); } } // Support both a return type and a description. The return type // is anything up to the first space. $returnParts = explode(' ', $content, 2); $returnType = $returnParts[0]; // If the return type is void, make sure there is // no return statement in the function. if ($returnType === 'void') { if (isset($tokens[$stackPtr]['scope_closer']) === true) { $endToken = $tokens[$stackPtr]['scope_closer']; for ($returnToken = $stackPtr; $returnToken < $endToken; $returnToken++) { if ($tokens[$returnToken]['code'] === T_CLOSURE) { $returnToken = $tokens[$returnToken]['scope_closer']; continue; } if ($tokens[$returnToken]['code'] === T_RETURN || $tokens[$returnToken]['code'] === T_YIELD) { break; } } if ($returnToken !== $endToken) { // If the function is not returning anything, just // exiting, then there is no problem. $semicolon = $phpcsFile->findNext(T_WHITESPACE, $returnToken + 1, null, true); if ($tokens[$semicolon]['code'] !== T_SEMICOLON) { $error = 'Function return type is void, but function contains return statement'; $phpcsFile->addError($error, $return, 'InvalidReturnVoid'); } } } //end if } else { if ($returnType !== 'mixed') { // If return type is not void, there needs to be a return statement // somewhere in the function that returns something. if (isset($tokens[$stackPtr]['scope_closer']) === true) { $endToken = $tokens[$stackPtr]['scope_closer']; $returnToken = $phpcsFile->findNext(array(T_RETURN, T_YIELD), $stackPtr, $endToken); if ($returnToken === false) { $error = 'Function return type is not void, but function has no return statement'; $phpcsFile->addError($error, $return, 'InvalidNoReturn'); } else { $semicolon = $phpcsFile->findNext(T_WHITESPACE, $returnToken + 1, null, true); if ($tokens[$semicolon]['code'] === T_SEMICOLON) { $error = 'Function return type is not void, but function is returning void here'; $phpcsFile->addError($error, $returnToken, 'InvalidReturnNotVoid'); } } } } } //end if } //end if } else { $error = 'Missing @return tag in function comment'; $phpcsFile->addError($error, $tokens[$commentStart]['comment_closer'], 'MissingReturn'); } //end if }
/** * Processes the function tokens within the class. * * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. * @param int $stackPtr The position where the token was found. * @param int $currScope The current scope opener token. * * @return void */ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) { $tokens = $phpcsFile->getTokens(); $methodName = $phpcsFile->getDeclarationName($stackPtr); if ($methodName === null) { // Ignore closures. return; } if ($methodName[0] === '_' && isset($methodName[1]) === true && $methodName[1] !== '_') { $error = 'Method name "%s" should not be prefixed with an underscore to indicate visibility'; $data = array($methodName); $phpcsFile->addWarning($error, $stackPtr, 'Underscore', $data); } $visibility = 0; $static = 0; $abstract = 0; $final = 0; $find = Tokens::$methodPrefixes; $find[] = T_WHITESPACE; $prev = $phpcsFile->findPrevious($find, $stackPtr - 1, null, true); $prefix = $stackPtr; while (($prefix = $phpcsFile->findPrevious(Tokens::$methodPrefixes, $prefix - 1, $prev)) !== false) { switch ($tokens[$prefix]['code']) { case T_STATIC: $static = $prefix; break; case T_ABSTRACT: $abstract = $prefix; break; case T_FINAL: $final = $prefix; break; default: $visibility = $prefix; break; } } $fixes = array(); if ($visibility !== 0 && $final > $visibility) { $error = 'The final declaration must precede the visibility declaration'; $fix = $phpcsFile->addFixableError($error, $final, 'FinalAfterVisibility'); if ($fix === true) { $fixes[$final] = ''; $fixes[$final + 1] = ''; if (isset($fixes[$visibility]) === true) { $fixes[$visibility] = 'final ' . $fixes[$visibility]; } else { $fixes[$visibility] = 'final ' . $tokens[$visibility]['content']; } } } if ($visibility !== 0 && $abstract > $visibility) { $error = 'The abstract declaration must precede the visibility declaration'; $fix = $phpcsFile->addFixableError($error, $abstract, 'AbstractAfterVisibility'); if ($fix === true) { $fixes[$abstract] = ''; $fixes[$abstract + 1] = ''; if (isset($fixes[$visibility]) === true) { $fixes[$visibility] = 'abstract ' . $fixes[$visibility]; } else { $fixes[$visibility] = 'abstract ' . $tokens[$visibility]['content']; } } } if ($static !== 0 && $static < $visibility) { $error = 'The static declaration must come after the visibility declaration'; $fix = $phpcsFile->addFixableError($error, $static, 'StaticBeforeVisibility'); if ($fix === true) { $fixes[$static] = ''; $fixes[$static + 1] = ''; if (isset($fixes[$visibility]) === true) { $fixes[$visibility] = $fixes[$visibility] . ' static'; } else { $fixes[$visibility] = $tokens[$visibility]['content'] . ' static'; } } } // Batch all the fixes together to reduce the possibility of conflicts. if (empty($fixes) === false) { $phpcsFile->fixer->beginChangeset(); foreach ($fixes as $stackPtr => $content) { $phpcsFile->fixer->replaceToken($stackPtr, $content); } $phpcsFile->fixer->endChangeset(); } }
/** * Processes this test, when one of its tokens is encountered. * * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * * @return void */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $token = $tokens[$stackPtr]; // Skip function without body. if (isset($token['scope_opener']) === false) { return; } // Get function name. $methodName = $phpcsFile->getDeclarationName($stackPtr); // Get all parameters from method signature. $signature = array(); foreach ($phpcsFile->getMethodParameters($stackPtr) as $param) { $signature[] = $param['name']; } $next = ++$token['scope_opener']; $end = --$token['scope_closer']; for (; $next <= $end; ++$next) { $code = $tokens[$next]['code']; if (isset(Tokens::$emptyTokens[$code]) === true) { continue; } else { if ($code === T_RETURN) { continue; } } break; } // Any token except 'parent' indicates correct code. if ($tokens[$next]['code'] !== T_PARENT) { return; } // Find next non empty token index, should be double colon. $next = $phpcsFile->findNext(Tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code. if ($next === false || $tokens[$next]['code'] !== T_DOUBLE_COLON) { return; } // Find next non empty token index, should be the function name. $next = $phpcsFile->findNext(Tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code or other method. if ($next === false || $tokens[$next]['content'] !== $methodName) { return; } // Find next non empty token index, should be the open parenthesis. $next = $phpcsFile->findNext(Tokens::$emptyTokens, $next + 1, null, true); // Skip for invalid code. if ($next === false || $tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { return; } $validParameterTypes = array(T_VARIABLE, T_LNUMBER, T_CONSTANT_ENCAPSED_STRING); $parameters = array(''); $parenthesisCount = 1; $count = count($tokens); for (++$next; $next < $count; ++$next) { $code = $tokens[$next]['code']; if ($code === T_OPEN_PARENTHESIS) { ++$parenthesisCount; } else { if ($code === T_CLOSE_PARENTHESIS) { --$parenthesisCount; } else { if ($parenthesisCount === 1 && $code === T_COMMA) { $parameters[] = ''; } else { if (isset(Tokens::$emptyTokens[$code]) === false) { $parameters[count($parameters) - 1] .= $tokens[$next]['content']; } } } } if ($parenthesisCount === 0) { break; } } //end for $next = $phpcsFile->findNext(Tokens::$emptyTokens, $next + 1, null, true); if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { return; } // Check rest of the scope. for (++$next; $next <= $end; ++$next) { $code = $tokens[$next]['code']; // Skip for any other content. if (isset(Tokens::$emptyTokens[$code]) === false) { return; } } $parameters = array_map('trim', $parameters); $parameters = array_filter($parameters); if (count($parameters) === count($signature) && $parameters === $signature) { $phpcsFile->addWarning('Possible useless method overriding detected', $stackPtr, 'Found'); } }