1<?php 2/** 3 * Squiz_Sniffs_NamingConventions_ValidVariableNameSniff. 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_AbstractVariableSniff', true) === false) { 17 throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractVariableSniff not found'); 18} 19 20/** 21 * Squiz_Sniffs_NamingConventions_ValidVariableNameSniff. 22 * 23 * Checks the naming of variables and member variables. 24 * 25 * @category PHP 26 * @package PHP_CodeSniffer 27 * @author Greg Sherwood <gsherwood@squiz.net> 28 * @author Marc McIntyre <mmcintyre@squiz.net> 29 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 30 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 31 * @version Release: @package_version@ 32 * @link http://pear.php.net/package/PHP_CodeSniffer 33 */ 34class Squiz_Sniffs_NamingConventions_ValidVariableNameSniff extends PHP_CodeSniffer_Standards_AbstractVariableSniff 35{ 36 37 /** 38 * Tokens to ignore so that we can find a DOUBLE_COLON. 39 * 40 * @var array 41 */ 42 private $_ignore = array( 43 T_WHITESPACE, 44 T_COMMENT, 45 ); 46 47 48 /** 49 * Processes this test, when one of its tokens is encountered. 50 * 51 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 52 * @param int $stackPtr The position of the current token in the 53 * stack passed in $tokens. 54 * 55 * @return void 56 */ 57 protected function processVariable(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 58 { 59 $tokens = $phpcsFile->getTokens(); 60 $varName = ltrim($tokens[$stackPtr]['content'], '$'); 61 62 $phpReservedVars = array( 63 '_SERVER', 64 '_GET', 65 '_POST', 66 '_REQUEST', 67 '_SESSION', 68 '_ENV', 69 '_COOKIE', 70 '_FILES', 71 'GLOBALS', 72 'http_response_header', 73 'HTTP_RAW_POST_DATA', 74 'php_errormsg', 75 ); 76 77 // If it's a php reserved var, then its ok. 78 if (in_array($varName, $phpReservedVars) === true) { 79 return; 80 } 81 82 $objOperator = $phpcsFile->findNext(array(T_WHITESPACE), ($stackPtr + 1), null, true); 83 if ($tokens[$objOperator]['code'] === T_OBJECT_OPERATOR) { 84 // Check to see if we are using a variable from an object. 85 $var = $phpcsFile->findNext(array(T_WHITESPACE), ($objOperator + 1), null, true); 86 if ($tokens[$var]['code'] === T_STRING) { 87 $bracket = $phpcsFile->findNext(array(T_WHITESPACE), ($var + 1), null, true); 88 if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { 89 $objVarName = $tokens[$var]['content']; 90 91 // There is no way for us to know if the var is public or 92 // private, so we have to ignore a leading underscore if there is 93 // one and just check the main part of the variable name. 94 $originalVarName = $objVarName; 95 if (substr($objVarName, 0, 1) === '_') { 96 $objVarName = substr($objVarName, 1); 97 } 98 99 if (PHP_CodeSniffer::isCamelCaps($objVarName, false, true, false) === false) { 100 $error = 'Variable "%s" is not in valid camel caps format'; 101 $data = array($originalVarName); 102 $phpcsFile->addError($error, $var, 'NotCamelCaps', $data); 103 } 104 }//end if 105 }//end if 106 }//end if 107 108 // There is no way for us to know if the var is public or private, 109 // so we have to ignore a leading underscore if there is one and just 110 // check the main part of the variable name. 111 $originalVarName = $varName; 112 if (substr($varName, 0, 1) === '_') { 113 $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), ($stackPtr - 1), null, true); 114 if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { 115 // The variable lives within a class, and is referenced like 116 // this: MyClass::$_variable, so we don't know its scope. 117 $inClass = true; 118 } else { 119 $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE, T_TRAIT)); 120 } 121 122 if ($inClass === true) { 123 $varName = substr($varName, 1); 124 } 125 } 126 127 if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { 128 $error = 'Variable "%s" is not in valid camel caps format'; 129 $data = array($originalVarName); 130 $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); 131 } 132 133 }//end processVariable() 134 135 136 /** 137 * Processes class member variables. 138 * 139 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 140 * @param int $stackPtr The position of the current token in the 141 * stack passed in $tokens. 142 * 143 * @return void 144 */ 145 protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 146 { 147 $tokens = $phpcsFile->getTokens(); 148 149 $varName = ltrim($tokens[$stackPtr]['content'], '$'); 150 $memberProps = $phpcsFile->getMemberProperties($stackPtr); 151 if (empty($memberProps) === true) { 152 // Couldn't get any info about this variable, which 153 // generally means it is invalid or possibly has a parse 154 // error. Any errors will be reported by the core, so 155 // we can ignore it. 156 return; 157 } 158 159 $public = ($memberProps['scope'] !== 'private'); 160 $errorData = array($varName); 161 162 if ($public === true) { 163 if (substr($varName, 0, 1) === '_') { 164 $error = '%s member variable "%s" must not contain a leading underscore'; 165 $data = array( 166 ucfirst($memberProps['scope']), 167 $errorData[0], 168 ); 169 $phpcsFile->addError($error, $stackPtr, 'PublicHasUnderscore', $data); 170 return; 171 } 172 } else { 173 if (substr($varName, 0, 1) !== '_') { 174 $error = 'Private member variable "%s" must contain a leading underscore'; 175 $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $errorData); 176 return; 177 } 178 } 179 180 if (PHP_CodeSniffer::isCamelCaps($varName, false, $public, false) === false) { 181 $error = 'Member variable "%s" is not in valid camel caps format'; 182 $phpcsFile->addError($error, $stackPtr, 'MemberNotCamelCaps', $errorData); 183 } 184 185 }//end processMemberVar() 186 187 188 /** 189 * Processes the variable found within a double quoted string. 190 * 191 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 192 * @param int $stackPtr The position of the double quoted 193 * string. 194 * 195 * @return void 196 */ 197 protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 198 { 199 $tokens = $phpcsFile->getTokens(); 200 201 $phpReservedVars = array( 202 '_SERVER', 203 '_GET', 204 '_POST', 205 '_REQUEST', 206 '_SESSION', 207 '_ENV', 208 '_COOKIE', 209 '_FILES', 210 'GLOBALS', 211 'http_response_header', 212 'HTTP_RAW_POST_DATA', 213 'php_errormsg', 214 ); 215 216 if (preg_match_all('|[^\\\]\${?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) { 217 foreach ($matches[1] as $varName) { 218 // If it's a php reserved var, then its ok. 219 if (in_array($varName, $phpReservedVars) === true) { 220 continue; 221 } 222 223 if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { 224 $error = 'Variable "%s" is not in valid camel caps format'; 225 $data = array($varName); 226 $phpcsFile->addError($error, $stackPtr, 'StringNotCamelCaps', $data); 227 } 228 } 229 } 230 231 }//end processVariableInString() 232 233 234}//end class 235