1<?php 2/** 3 * A class to find T_VARIABLE tokens. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @author Marc McIntyre <mmcintyre@squiz.net> 11 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 12 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 13 * @link http://pear.php.net/package/PHP_CodeSniffer 14 */ 15 16if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { 17 $error = 'Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'; 18 throw new PHP_CodeSniffer_Exception($error); 19} 20 21/** 22 * A class to find T_VARIABLE tokens. 23 * 24 * This class can distinguish between normal T_VARIABLE tokens, and those tokens 25 * that represent class members. If a class member is encountered, then the 26 * processMemberVar method is called so the extending class can process it. If 27 * the token is found to be a normal T_VARIABLE token, then processVariable is 28 * called. 29 * 30 * @category PHP 31 * @package PHP_CodeSniffer 32 * @author Greg Sherwood <gsherwood@squiz.net> 33 * @author Marc McIntyre <mmcintyre@squiz.net> 34 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 35 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 36 * @version Release: @package_version@ 37 * @link http://pear.php.net/package/PHP_CodeSniffer 38 */ 39abstract class PHP_CodeSniffer_Standards_AbstractVariableSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff 40{ 41 42 /** 43 * The end token of the current function that we are in. 44 * 45 * @var int 46 */ 47 private $_endFunction = -1; 48 49 /** 50 * TRUE if a function is currently open. 51 * 52 * @var boolean 53 */ 54 private $_functionOpen = false; 55 56 /** 57 * The current PHP_CodeSniffer file that we are processing. 58 * 59 * @var PHP_CodeSniffer_File 60 */ 61 protected $currentFile = null; 62 63 64 /** 65 * Constructs an AbstractVariableTest. 66 */ 67 public function __construct() 68 { 69 $scopes = array( 70 T_CLASS, 71 T_ANON_CLASS, 72 T_TRAIT, 73 T_INTERFACE, 74 ); 75 76 $listen = array( 77 T_FUNCTION, 78 T_VARIABLE, 79 T_DOUBLE_QUOTED_STRING, 80 T_HEREDOC, 81 ); 82 83 parent::__construct($scopes, $listen, true); 84 85 }//end __construct() 86 87 88 /** 89 * Processes the token in the specified PHP_CodeSniffer_File. 90 * 91 * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this 92 * token was found. 93 * @param int $stackPtr The position where the token was found. 94 * @param array $currScope The current scope opener token. 95 * 96 * @return void 97 */ 98 protected final function processTokenWithinScope( 99 PHP_CodeSniffer_File $phpcsFile, 100 $stackPtr, 101 $currScope 102 ) { 103 if ($this->currentFile !== $phpcsFile) { 104 $this->currentFile = $phpcsFile; 105 $this->_functionOpen = false; 106 $this->_endFunction = -1; 107 } 108 109 $tokens = $phpcsFile->getTokens(); 110 111 if ($stackPtr > $this->_endFunction) { 112 $this->_functionOpen = false; 113 } 114 115 if ($tokens[$stackPtr]['code'] === T_FUNCTION 116 && $this->_functionOpen === false 117 ) { 118 $this->_functionOpen = true; 119 120 $methodProps = $phpcsFile->getMethodProperties($stackPtr); 121 122 // If the function is abstract, or is in an interface, 123 // then set the end of the function to it's closing semicolon. 124 if ($methodProps['is_abstract'] === true 125 || $tokens[$currScope]['code'] === T_INTERFACE 126 ) { 127 $this->_endFunction 128 = $phpcsFile->findNext(array(T_SEMICOLON), $stackPtr); 129 } else { 130 if (isset($tokens[$stackPtr]['scope_closer']) === false) { 131 $error = 'Possible parse error: non-abstract method defined as abstract'; 132 $phpcsFile->addWarning($error, $stackPtr); 133 return; 134 } 135 136 $this->_endFunction = $tokens[$stackPtr]['scope_closer']; 137 } 138 }//end if 139 140 if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING 141 || $tokens[$stackPtr]['code'] === T_HEREDOC 142 ) { 143 // Check to see if this string has a variable in it. 144 $pattern = '|(?<!\\\\)(?:\\\\{2})*\${?[a-zA-Z0-9_]+}?|'; 145 if (preg_match($pattern, $tokens[$stackPtr]['content']) !== 0) { 146 $this->processVariableInString($phpcsFile, $stackPtr); 147 } 148 149 return; 150 } 151 152 if ($this->_functionOpen === true) { 153 if ($tokens[$stackPtr]['code'] === T_VARIABLE) { 154 $this->processVariable($phpcsFile, $stackPtr); 155 } 156 } else { 157 // What if we assign a member variable to another? 158 // ie. private $_count = $this->_otherCount + 1;. 159 $this->processMemberVar($phpcsFile, $stackPtr); 160 } 161 162 }//end processTokenWithinScope() 163 164 165 /** 166 * Processes the token outside the scope in the file. 167 * 168 * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this 169 * token was found. 170 * @param int $stackPtr The position where the token was found. 171 * 172 * @return void 173 */ 174 protected final function processTokenOutsideScope( 175 PHP_CodeSniffer_File $phpcsFile, 176 $stackPtr 177 ) { 178 $tokens = $phpcsFile->getTokens(); 179 // These variables are not member vars. 180 if ($tokens[$stackPtr]['code'] === T_VARIABLE) { 181 $this->processVariable($phpcsFile, $stackPtr); 182 } else if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING 183 || $tokens[$stackPtr]['code'] === T_HEREDOC 184 ) { 185 // Check to see if this string has a variable in it. 186 $pattern = '|(?<!\\\\)(?:\\\\{2})*\${?[a-zA-Z0-9_]+}?|'; 187 if (preg_match($pattern, $tokens[$stackPtr]['content']) !== 0) { 188 $this->processVariableInString($phpcsFile, $stackPtr); 189 } 190 } 191 192 }//end processTokenOutsideScope() 193 194 195 /** 196 * Called to process class member vars. 197 * 198 * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this 199 * token was found. 200 * @param int $stackPtr The position where the token was found. 201 * 202 * @return void 203 */ 204 abstract protected function processMemberVar( 205 PHP_CodeSniffer_File $phpcsFile, 206 $stackPtr 207 ); 208 209 210 /** 211 * Called to process normal member vars. 212 * 213 * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this 214 * token was found. 215 * @param int $stackPtr The position where the token was found. 216 * 217 * @return void 218 */ 219 abstract protected function processVariable( 220 PHP_CodeSniffer_File $phpcsFile, 221 $stackPtr 222 ); 223 224 225 /** 226 * Called to process variables found in double quoted strings or heredocs. 227 * 228 * Note that there may be more than one variable in the string, which will 229 * result only in one call for the string or one call per line for heredocs. 230 * 231 * @param PHP_CodeSniffer_File $phpcsFile The PHP_CodeSniffer file where this 232 * token was found. 233 * @param int $stackPtr The position where the double quoted 234 * string was found. 235 * 236 * @return void 237 */ 238 abstract protected function processVariableInString( 239 PHP_CodeSniffer_File 240 $phpcsFile, 241 $stackPtr 242 ); 243 244 245}//end class 246