Chris@17: Chris@17: * class ClassScopeTest extends PHP_CodeSniffer_Standards_AbstractScopeSniff Chris@17: * { Chris@17: * public function __construct() Chris@17: * { Chris@17: * parent::__construct(array(T_CLASS), array(T_FUNCTION)); Chris@17: * } Chris@17: * Chris@17: * protected function processTokenWithinScope(\PHP_CodeSniffer\Files\File $phpcsFile, $stackPtr, $currScope) Chris@17: * { Chris@17: * $className = $phpcsFile->getDeclarationName($currScope); Chris@17: * echo 'encountered a method within class '.$className; Chris@17: * } Chris@17: * } Chris@17: * Chris@17: * Chris@17: * @author Greg Sherwood 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\Exceptions\RuntimeException; Chris@17: Chris@17: abstract class AbstractScopeSniff implements Sniff Chris@17: { Chris@17: Chris@17: /** Chris@17: * The token types that this test wishes to listen to within the scope. Chris@17: * Chris@17: * @var array Chris@17: */ Chris@17: private $tokens = []; Chris@17: Chris@17: /** Chris@17: * The type of scope opener tokens that this test wishes to listen to. Chris@17: * Chris@17: * @var string Chris@17: */ Chris@17: private $scopeTokens = []; Chris@17: Chris@17: /** Chris@17: * True if this test should fire on tokens outside of the scope. Chris@17: * Chris@17: * @var boolean Chris@17: */ Chris@17: private $listenOutside = false; Chris@17: Chris@17: Chris@17: /** Chris@17: * Constructs a new AbstractScopeTest. Chris@17: * Chris@17: * @param array $scopeTokens The type of scope the test wishes to listen to. Chris@17: * @param array $tokens The tokens that the test wishes to listen to Chris@17: * within the scope. Chris@17: * @param boolean $listenOutside If true this test will also alert the Chris@17: * extending class when a token is found outside Chris@17: * the scope, by calling the Chris@17: * processTokenOutsideScope method. Chris@17: * Chris@17: * @see PHP_CodeSniffer.getValidScopeTokeners() Chris@17: * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If the specified tokens array is empty. Chris@17: */ Chris@17: public function __construct( Chris@17: array $scopeTokens, Chris@17: array $tokens, Chris@17: $listenOutside=false Chris@17: ) { Chris@17: if (empty($scopeTokens) === true) { Chris@17: $error = 'The scope tokens list cannot be empty'; Chris@17: throw new RuntimeException($error); Chris@17: } Chris@17: Chris@17: if (empty($tokens) === true) { Chris@17: $error = 'The tokens list cannot be empty'; Chris@17: throw new RuntimeException($error); Chris@17: } Chris@17: Chris@17: $invalidScopeTokens = array_intersect($scopeTokens, $tokens); Chris@17: if (empty($invalidScopeTokens) === false) { Chris@17: $invalid = implode(', ', $invalidScopeTokens); Chris@17: $error = "Scope tokens [$invalid] can't be in the tokens array"; Chris@17: throw new RuntimeException($error); Chris@17: } Chris@17: Chris@17: $this->listenOutside = $listenOutside; Chris@17: $this->scopeTokens = array_flip($scopeTokens); Chris@17: $this->tokens = $tokens; Chris@17: Chris@17: }//end __construct() Chris@17: Chris@17: Chris@17: /** Chris@17: * The method that is called to register the tokens this test wishes to Chris@17: * listen to. Chris@17: * Chris@17: * DO NOT OVERRIDE THIS METHOD. Use the constructor of this class to register Chris@17: * for the desired tokens and scope. Chris@17: * Chris@17: * @return int[] Chris@17: * @see __constructor() Chris@17: */ Chris@17: final public function register() Chris@17: { Chris@17: return $this->tokens; Chris@17: Chris@17: }//end register() Chris@17: Chris@17: Chris@17: /** Chris@17: * Processes the tokens that this test is listening for. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. Chris@17: * @param int $stackPtr The position in the stack where this Chris@17: * 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: * @see processTokenWithinScope() Chris@17: */ Chris@17: final public function process(File $phpcsFile, $stackPtr) Chris@17: { Chris@17: $tokens = $phpcsFile->getTokens(); Chris@17: Chris@17: $foundScope = false; Chris@17: $skipPtrs = []; Chris@17: foreach ($tokens[$stackPtr]['conditions'] as $scope => $code) { Chris@17: if (isset($this->scopeTokens[$code]) === true) { Chris@17: $skipPtrs[] = $this->processTokenWithinScope($phpcsFile, $stackPtr, $scope); Chris@17: $foundScope = true; Chris@17: } Chris@17: } Chris@17: Chris@17: if ($this->listenOutside === true && $foundScope === false) { Chris@17: $skipPtrs[] = $this->processTokenOutsideScope($phpcsFile, $stackPtr); Chris@17: } Chris@17: Chris@17: if (empty($skipPtrs) === false) { Chris@17: return min($skipPtrs); Chris@17: } Chris@17: Chris@17: return; Chris@17: Chris@17: }//end process() Chris@17: Chris@17: Chris@17: /** Chris@17: * Processes a token that is found within the scope that this test is Chris@17: * listening to. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. Chris@17: * @param int $stackPtr The position in the stack where this Chris@17: * token was found. Chris@17: * @param int $currScope The position in the tokens array that Chris@17: * opened the scope that this test is Chris@17: * listening for. 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 processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope); Chris@17: Chris@17: Chris@17: /** Chris@17: * Processes a token that is found outside the scope that this test is Chris@17: * listening to. Chris@17: * Chris@17: * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found. Chris@17: * @param int $stackPtr The position in the stack where this Chris@17: * 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 (count($tokens) + 1) to skip Chris@17: * the rest of the file. Chris@17: */ Chris@17: abstract protected function processTokenOutsideScope(File $phpcsFile, $stackPtr); Chris@17: Chris@17: Chris@17: }//end class