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 Zend_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 // Either a var name or a function call, so check for bracket. 88 $bracket = $phpcsFile->findNext(array(T_WHITESPACE), ($var + 1), null, true); 89 90 if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) { 91 $objVarName = $tokens[$var]['content']; 92 93 // There is no way for us to know if the var is public or private, 94 // so we have to ignore a leading underscore if there is one and just 95 // check the main part of the variable name. 96 $originalVarName = $objVarName; 97 if (substr($objVarName, 0, 1) === '_') { 98 $objVarName = substr($objVarName, 1); 99 } 100 101 if (PHP_CodeSniffer::isCamelCaps($objVarName, false, true, false) === false) { 102 $error = 'Variable "%s" is not in valid camel caps format'; 103 $data = array($originalVarName); 104 $phpcsFile->addError($error, $var, 'NotCamelCaps', $data); 105 } else if (preg_match('|\d|', $objVarName) === 1) { 106 $warning = 'Variable "%s" contains numbers but this is discouraged'; 107 $data = array($originalVarName); 108 $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); 109 } 110 }//end if 111 }//end if 112 }//end if 113 114 // There is no way for us to know if the var is public or private, 115 // so we have to ignore a leading underscore if there is one and just 116 // check the main part of the variable name. 117 $originalVarName = $varName; 118 if (substr($varName, 0, 1) === '_') { 119 $objOperator = $phpcsFile->findPrevious(array(T_WHITESPACE), ($stackPtr - 1), null, true); 120 if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) { 121 // The variable lives within a class, and is referenced like 122 // this: MyClass::$_variable, so we don't know its scope. 123 $inClass = true; 124 } else { 125 $inClass = $phpcsFile->hasCondition($stackPtr, array(T_CLASS, T_INTERFACE, T_TRAIT)); 126 } 127 128 if ($inClass === true) { 129 $varName = substr($varName, 1); 130 } 131 } 132 133 if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { 134 $error = 'Variable "%s" is not in valid camel caps format'; 135 $data = array($originalVarName); 136 $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); 137 } else if (preg_match('|\d|', $varName) === 1) { 138 $warning = 'Variable "%s" contains numbers but this is discouraged'; 139 $data = array($originalVarName); 140 $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data); 141 } 142 143 }//end processVariable() 144 145 146 /** 147 * Processes class member variables. 148 * 149 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 150 * @param int $stackPtr The position of the current token in the 151 * stack passed in $tokens. 152 * 153 * @return void 154 */ 155 protected function processMemberVar(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 156 { 157 $tokens = $phpcsFile->getTokens(); 158 $varName = ltrim($tokens[$stackPtr]['content'], '$'); 159 $memberProps = $phpcsFile->getMemberProperties($stackPtr); 160 $public = ($memberProps['scope'] === 'public'); 161 162 if ($public === true) { 163 if (substr($varName, 0, 1) === '_') { 164 $error = 'Public member variable "%s" must not contain a leading underscore'; 165 $data = array($varName); 166 $phpcsFile->addError($error, $stackPtr, 'PublicHasUnderscore', $data); 167 return; 168 } 169 } else { 170 if (substr($varName, 0, 1) !== '_') { 171 $scope = ucfirst($memberProps['scope']); 172 $error = '%s member variable "%s" must contain a leading underscore'; 173 $data = array( 174 $scope, 175 $varName, 176 ); 177 $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $data); 178 return; 179 } 180 } 181 182 if (PHP_CodeSniffer::isCamelCaps($varName, false, $public, false) === false) { 183 $error = 'Member variable "%s" is not in valid camel caps format'; 184 $data = array($varName); 185 $phpcsFile->addError($error, $stackPtr, 'MemberVarNotCamelCaps', $data); 186 } else if (preg_match('|\d|', $varName) === 1) { 187 $warning = 'Member variable "%s" contains numbers but this is discouraged'; 188 $data = array($varName); 189 $phpcsFile->addWarning($warning, $stackPtr, 'MemberVarContainsNumbers', $data); 190 } 191 192 }//end processMemberVar() 193 194 195 /** 196 * Processes the variable found within a double quoted string. 197 * 198 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 199 * @param int $stackPtr The position of the double quoted 200 * string. 201 * 202 * @return void 203 */ 204 protected function processVariableInString(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 205 { 206 $tokens = $phpcsFile->getTokens(); 207 208 $phpReservedVars = array( 209 '_SERVER', 210 '_GET', 211 '_POST', 212 '_REQUEST', 213 '_SESSION', 214 '_ENV', 215 '_COOKIE', 216 '_FILES', 217 'GLOBALS', 218 'http_response_header', 219 'HTTP_RAW_POST_DATA', 220 'php_errormsg', 221 ); 222 223 if (preg_match_all('|[^\\\]\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) { 224 foreach ($matches[1] as $varName) { 225 // If it's a php reserved var, then its ok. 226 if (in_array($varName, $phpReservedVars) === true) { 227 continue; 228 } 229 230 if (PHP_CodeSniffer::isCamelCaps($varName, false, true, false) === false) { 231 $error = 'Variable "%s" is not in valid camel caps format'; 232 $data = array($varName); 233 $phpcsFile->addError($error, $stackPtr, 'StringVarNotCamelCaps', $data); 234 } else if (preg_match('|\d|', $varName) === 1) { 235 $warning = 'Variable "%s" contains numbers but this is discouraged'; 236 $data = array($varName); 237 $phpcsFile->addWarning($warning, $stackPtr, 'StringVarContainsNumbers', $data); 238 } 239 }//end foreach 240 }//end if 241 242 }//end processVariableInString() 243 244 245}//end class 246