1<?php 2/** 3 * An AbstractScopeTest allows for tests that extend from this class to 4 * listen for tokens within a particular scope. 5 * 6 * PHP version 5 7 * 8 * @category PHP 9 * @package PHP_CodeSniffer 10 * @author Greg Sherwood <gsherwood@squiz.net> 11 * @author Marc McIntyre <mmcintyre@squiz.net> 12 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 13 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 14 * @link http://pear.php.net/package/PHP_CodeSniffer 15 */ 16 17/** 18 * An AbstractScopeTest allows for tests that extend from this class to 19 * listen for tokens within a particular scope. 20 * 21 * Below is a test that listens to methods that exist only within classes: 22 * <code> 23 * class ClassScopeTest extends PHP_CodeSniffer_Standards_AbstractScopeSniff 24 * { 25 * public function __construct() 26 * { 27 * parent::__construct(array(T_CLASS), array(T_FUNCTION)); 28 * } 29 * 30 * protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $) 31 * { 32 * $className = $phpcsFile->getDeclarationName($currScope); 33 * echo 'encountered a method within class '.$className; 34 * } 35 * } 36 * </code> 37 * 38 * @category PHP 39 * @package PHP_CodeSniffer 40 * @author Greg Sherwood <gsherwood@squiz.net> 41 * @author Marc McIntyre <mmcintyre@squiz.net> 42 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 43 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 44 * @version Release: @package_version@ 45 * @link http://pear.php.net/package/PHP_CodeSniffer 46 */ 47abstract class PHP_CodeSniffer_Standards_AbstractScopeSniff implements PHP_CodeSniffer_Sniff 48{ 49 50 /** 51 * The token types that this test wishes to listen to within the scope. 52 * 53 * @var array 54 */ 55 private $_tokens = array(); 56 57 /** 58 * The type of scope opener tokens that this test wishes to listen to. 59 * 60 * @var string 61 */ 62 private $_scopeTokens = array(); 63 64 /** 65 * True if this test should fire on tokens outside of the scope. 66 * 67 * @var boolean 68 */ 69 private $_listenOutside = false; 70 71 72 /** 73 * Constructs a new AbstractScopeTest. 74 * 75 * @param array $scopeTokens The type of scope the test wishes to listen to. 76 * @param array $tokens The tokens that the test wishes to listen to 77 * within the scope. 78 * @param boolean $listenOutside If true this test will also alert the 79 * extending class when a token is found outside 80 * the scope, by calling the 81 * processTokenOutsideScope method. 82 * 83 * @see PHP_CodeSniffer.getValidScopeTokeners() 84 * @throws PHP_CodeSniffer_Exception If the specified tokens array is empty. 85 */ 86 public function __construct( 87 array $scopeTokens, 88 array $tokens, 89 $listenOutside=false 90 ) { 91 if (empty($scopeTokens) === true) { 92 $error = 'The scope tokens list cannot be empty'; 93 throw new PHP_CodeSniffer_Exception($error); 94 } 95 96 if (empty($tokens) === true) { 97 $error = 'The tokens list cannot be empty'; 98 throw new PHP_CodeSniffer_Exception($error); 99 } 100 101 $invalidScopeTokens = array_intersect($scopeTokens, $tokens); 102 if (empty($invalidScopeTokens) === false) { 103 $invalid = implode(', ', $invalidScopeTokens); 104 $error = "Scope tokens [$invalid] can't be in the tokens array"; 105 throw new PHP_CodeSniffer_Exception($error); 106 } 107 108 $this->_listenOutside = $listenOutside; 109 $this->_scopeTokens = array_flip($scopeTokens); 110 $this->_tokens = $tokens; 111 112 }//end __construct() 113 114 115 /** 116 * The method that is called to register the tokens this test wishes to 117 * listen to. 118 * 119 * DO NOT OVERRIDE THIS METHOD. Use the constructor of this class to register 120 * for the desired tokens and scope. 121 * 122 * @return int[] 123 * @see __constructor() 124 */ 125 public final function register() 126 { 127 return $this->_tokens; 128 129 }//end register() 130 131 132 /** 133 * Processes the tokens that this test is listening for. 134 * 135 * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. 136 * @param int $stackPtr The position in the stack where this 137 * token was found. 138 * 139 * @return void 140 * @see processTokenWithinScope() 141 */ 142 public final function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 143 { 144 $tokens = $phpcsFile->getTokens(); 145 146 $foundScope = false; 147 foreach ($tokens[$stackPtr]['conditions'] as $scope => $code) { 148 if (isset($this->_scopeTokens[$code]) === true) { 149 $this->processTokenWithinScope($phpcsFile, $stackPtr, $scope); 150 $foundScope = true; 151 } 152 } 153 154 if ($this->_listenOutside === true && $foundScope === false) { 155 $this->processTokenOutsideScope($phpcsFile, $stackPtr); 156 } 157 158 }//end process() 159 160 161 /** 162 * Processes a token that is found within the scope that this test is 163 * listening to. 164 * 165 * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. 166 * @param int $stackPtr The position in the stack where this 167 * token was found. 168 * @param int $currScope The position in the tokens array that 169 * opened the scope that this test is 170 * listening for. 171 * 172 * @return void 173 */ 174 protected abstract function processTokenWithinScope( 175 PHP_CodeSniffer_File $phpcsFile, 176 $stackPtr, 177 $currScope 178 ); 179 180 181 /** 182 * Processes a token that is found outside the scope that this test is 183 * listening to. 184 * 185 * @param PHP_CodeSniffer_File $phpcsFile The file where this token was found. 186 * @param int $stackPtr The position in the stack where this 187 * token was found. 188 * 189 * @return void 190 */ 191 protected function processTokenOutsideScope( 192 PHP_CodeSniffer_File $phpcsFile, 193 $stackPtr 194 ) { 195 196 }//end processTokenOutsideScope() 197 198 199}//end class 200