Chris@17: Chris@17: * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) Chris@17: * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence Chris@17: */ Chris@17: Chris@17: namespace PHP_CodeSniffer\Sniffs; Chris@17: Chris@17: use PHP_CodeSniffer\Files\File; Chris@17: use PHP_CodeSniffer\Util\Tokens; Chris@17: Chris@17: abstract class AbstractVariableSniff extends AbstractScopeSniff Chris@17: { Chris@17: Chris@17: Chris@17: /** Chris@17: * List of PHP Reserved variables. Chris@17: * Chris@17: * Used by various naming convention sniffs. Chris@17: * Chris@17: * @var array Chris@17: */ Chris@17: protected $phpReservedVars = [ Chris@17: '_SERVER' => true, Chris@17: '_GET' => true, Chris@17: '_POST' => true, Chris@17: '_REQUEST' => true, Chris@17: '_SESSION' => true, Chris@17: '_ENV' => true, Chris@17: '_COOKIE' => true, Chris@17: '_FILES' => true, Chris@17: 'GLOBALS' => true, Chris@17: 'http_response_header' => true, Chris@17: 'HTTP_RAW_POST_DATA' => true, Chris@17: 'php_errormsg' => true, Chris@17: ]; Chris@17: Chris@17: Chris@17: /** Chris@17: * Constructs an AbstractVariableTest. Chris@17: */ Chris@17: public function __construct() Chris@17: { Chris@17: $scopes = Tokens::$ooScopeTokens; Chris@17: Chris@17: $listen = [ Chris@17: T_VARIABLE, Chris@17: T_DOUBLE_QUOTED_STRING, Chris@17: T_HEREDOC, Chris@17: ]; Chris@17: Chris@17: parent::__construct($scopes, $listen, true); Chris@17: Chris@17: }//end __construct() Chris@17: Chris@17: Chris@17: /** Chris@18: * Processes the token in the specified PHP_CodeSniffer\Files\File. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this Chris@17: * token was found. Chris@17: * @param int $stackPtr The position where the token was found. Chris@17: * @param int $currScope The current scope opener token. Chris@17: * Chris@17: * @return void|int Optionally returns a stack pointer. The sniff will not be Chris@17: * called again on the current file until the returned stack Chris@17: * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip Chris@17: * the rest of the file. Chris@17: */ Chris@17: final protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) Chris@17: { Chris@17: $tokens = $phpcsFile->getTokens(); Chris@17: Chris@17: if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING Chris@17: || $tokens[$stackPtr]['code'] === T_HEREDOC Chris@17: ) { Chris@17: // Check to see if this string has a variable in it. Chris@17: $pattern = '|(?processVariableInString($phpcsFile, $stackPtr); Chris@17: } Chris@17: Chris@17: return; Chris@17: } Chris@17: Chris@18: // If this token is nested inside a function at a deeper Chris@17: // level than the current OO scope that was found, it's a normal Chris@17: // variable and not a member var. Chris@17: $conditions = array_reverse($tokens[$stackPtr]['conditions'], true); Chris@17: $inFunction = false; Chris@17: foreach ($conditions as $scope => $code) { Chris@17: if (isset(Tokens::$ooScopeTokens[$code]) === true) { Chris@17: break; Chris@17: } Chris@17: Chris@17: if ($code === T_FUNCTION || $code === T_CLOSURE) { Chris@17: $inFunction = true; Chris@17: } Chris@17: } Chris@17: Chris@17: if ($scope !== $currScope) { Chris@17: // We found a closer scope to this token, so ignore Chris@17: // this particular time through the sniff. We will process Chris@17: // this token when this closer scope is found to avoid Chris@17: // duplicate checks. Chris@17: return; Chris@17: } Chris@17: Chris@17: // Just make sure this isn't a variable in a function declaration. Chris@17: if ($inFunction === false && isset($tokens[$stackPtr]['nested_parenthesis']) === true) { Chris@17: foreach ($tokens[$stackPtr]['nested_parenthesis'] as $opener => $closer) { Chris@17: if (isset($tokens[$opener]['parenthesis_owner']) === false) { Chris@18: // Check if this is a USE statement for a closure. Chris@17: $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($opener - 1), null, true); Chris@17: if ($tokens[$prev]['code'] === T_USE) { Chris@17: $inFunction = true; Chris@17: break; Chris@17: } Chris@17: Chris@17: continue; Chris@17: } Chris@17: Chris@17: $owner = $tokens[$opener]['parenthesis_owner']; Chris@17: if ($tokens[$owner]['code'] === T_FUNCTION Chris@17: || $tokens[$owner]['code'] === T_CLOSURE Chris@17: ) { Chris@17: $inFunction = true; Chris@17: break; Chris@17: } Chris@17: } Chris@17: }//end if Chris@17: Chris@17: if ($inFunction === true) { Chris@17: return $this->processVariable($phpcsFile, $stackPtr); Chris@17: } else { Chris@17: return $this->processMemberVar($phpcsFile, $stackPtr); Chris@17: } Chris@17: Chris@17: }//end processTokenWithinScope() Chris@17: Chris@17: Chris@17: /** Chris@17: * Processes the token outside the scope in the file. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this Chris@17: * token was found. Chris@17: * @param int $stackPtr The position where the token was found. Chris@17: * Chris@17: * @return void|int Optionally returns a stack pointer. The sniff will not be Chris@17: * called again on the current file until the returned stack Chris@17: * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip Chris@17: * the rest of the file. Chris@17: */ Chris@17: final protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) Chris@17: { Chris@17: $tokens = $phpcsFile->getTokens(); Chris@17: // These variables are not member vars. Chris@17: if ($tokens[$stackPtr]['code'] === T_VARIABLE) { Chris@17: return $this->processVariable($phpcsFile, $stackPtr); Chris@17: } else if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING Chris@17: || $tokens[$stackPtr]['code'] === T_HEREDOC Chris@17: ) { Chris@17: // Check to see if this string has a variable in it. Chris@17: $pattern = '|(?processVariableInString($phpcsFile, $stackPtr); Chris@17: } Chris@17: } Chris@17: Chris@17: }//end processTokenOutsideScope() Chris@17: Chris@17: Chris@17: /** Chris@17: * Called to process class member vars. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this Chris@17: * token was found. Chris@17: * @param int $stackPtr The position where the token was found. Chris@17: * Chris@17: * @return void|int Optionally returns a stack pointer. The sniff will not be Chris@17: * called again on the current file until the returned stack Chris@17: * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip Chris@17: * the rest of the file. Chris@17: */ Chris@17: abstract protected function processMemberVar(File $phpcsFile, $stackPtr); Chris@17: Chris@17: Chris@17: /** Chris@17: * Called to process normal member vars. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this Chris@17: * token was found. Chris@17: * @param int $stackPtr The position where the token was found. Chris@17: * Chris@17: * @return void|int Optionally returns a stack pointer. The sniff will not be Chris@17: * called again on the current file until the returned stack Chris@17: * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip Chris@17: * the rest of the file. Chris@17: */ Chris@17: abstract protected function processVariable(File $phpcsFile, $stackPtr); Chris@17: Chris@17: Chris@17: /** Chris@17: * Called to process variables found in double quoted strings or heredocs. Chris@17: * Chris@17: * Note that there may be more than one variable in the string, which will Chris@17: * result only in one call for the string or one call per line for heredocs. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where this Chris@17: * token was found. Chris@17: * @param int $stackPtr The position where the double quoted Chris@17: * string was found. Chris@17: * Chris@17: * @return void|int Optionally returns a stack pointer. The sniff will not be Chris@17: * called again on the current file until the returned stack Chris@17: * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip Chris@17: * the rest of the file. Chris@17: */ Chris@17: abstract protected function processVariableInString(File $phpcsFile, $stackPtr); Chris@17: Chris@17: Chris@17: }//end class