1<?php 2/** 3 * Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff. 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 16/** 17 * Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff. 18 * 19 * Ensures that constant names are all uppercase. 20 * 21 * @category PHP 22 * @package PHP_CodeSniffer 23 * @author Greg Sherwood <gsherwood@squiz.net> 24 * @author Marc McIntyre <mmcintyre@squiz.net> 25 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 26 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 27 * @version Release: @package_version@ 28 * @link http://pear.php.net/package/PHP_CodeSniffer 29 */ 30class Generic_Sniffs_NamingConventions_UpperCaseConstantNameSniff implements PHP_CodeSniffer_Sniff 31{ 32 33 34 /** 35 * Returns an array of tokens this test wants to listen for. 36 * 37 * @return array 38 */ 39 public function register() 40 { 41 return array(T_STRING); 42 43 }//end register() 44 45 46 /** 47 * Processes this test, when one of its tokens is encountered. 48 * 49 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 50 * @param int $stackPtr The position of the current token in the 51 * stack passed in $tokens. 52 * 53 * @return void 54 */ 55 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 56 { 57 $tokens = $phpcsFile->getTokens(); 58 $constName = $tokens[$stackPtr]['content']; 59 60 // If this token is in a heredoc, ignore it. 61 if ($phpcsFile->hasCondition($stackPtr, T_START_HEREDOC) === true) { 62 return; 63 } 64 65 // Special case for PHP 5.5 class name resolution. 66 if (strtolower($constName) === 'class' 67 && $tokens[($stackPtr - 1)]['code'] === T_DOUBLE_COLON 68 ) { 69 return; 70 } 71 72 // Special case for PHPUnit. 73 if ($constName === 'PHPUnit_MAIN_METHOD') { 74 return; 75 } 76 77 // If the next non-whitespace token after this token 78 // is not an opening parenthesis then it is not a function call. 79 for ($openBracket = ($stackPtr + 1); $openBracket < $phpcsFile->numTokens; $openBracket++) { 80 if ($tokens[$openBracket]['code'] !== T_WHITESPACE) { 81 break; 82 } 83 } 84 85 if ($openBracket === $phpcsFile->numTokens) { 86 return; 87 } 88 89 if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { 90 $functionKeyword = $phpcsFile->findPrevious( 91 array( 92 T_WHITESPACE, 93 T_COMMA, 94 T_COMMENT, 95 T_STRING, 96 T_NS_SEPARATOR, 97 ), 98 ($stackPtr - 1), 99 null, 100 true 101 ); 102 103 if ($tokens[$functionKeyword]['code'] !== T_CONST) { 104 return; 105 } 106 107 // This is a class constant. 108 if (strtoupper($constName) !== $constName) { 109 if (strtolower($constName) === $constName) { 110 $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'lower'); 111 } else { 112 $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'mixed'); 113 } 114 115 $error = 'Class constants must be uppercase; expected %s but found %s'; 116 $data = array( 117 strtoupper($constName), 118 $constName, 119 ); 120 $phpcsFile->addError($error, $stackPtr, 'ClassConstantNotUpperCase', $data); 121 } else { 122 $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'upper'); 123 } 124 125 return; 126 }//end if 127 128 if (strtolower($constName) !== 'define') { 129 return; 130 } 131 132 /* 133 This may be a "define" function call. 134 */ 135 136 // Make sure this is not a method call. 137 $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); 138 if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR 139 || $tokens[$prev]['code'] === T_DOUBLE_COLON 140 ) { 141 return; 142 } 143 144 // The next non-whitespace token must be the constant name. 145 $constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); 146 if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { 147 return; 148 } 149 150 $constName = $tokens[$constPtr]['content']; 151 152 // Check for constants like self::CONSTANT. 153 $prefix = ''; 154 $splitPos = strpos($constName, '::'); 155 if ($splitPos !== false) { 156 $prefix = substr($constName, 0, ($splitPos + 2)); 157 $constName = substr($constName, ($splitPos + 2)); 158 } 159 160 // Strip namesspace from constant like /foo/bar/CONSTANT. 161 $splitPos = strrpos($constName, '\\'); 162 if ($splitPos !== false) { 163 $prefix = substr($constName, 0, ($splitPos + 1)); 164 $constName = substr($constName, ($splitPos + 1)); 165 } 166 167 if (strtoupper($constName) !== $constName) { 168 if (strtolower($constName) === $constName) { 169 $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'lower'); 170 } else { 171 $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'mixed'); 172 } 173 174 $error = 'Constants must be uppercase; expected %s but found %s'; 175 $data = array( 176 $prefix.strtoupper($constName), 177 $prefix.$constName, 178 ); 179 $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); 180 } else { 181 $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'upper'); 182 } 183 184 }//end process() 185 186 187}//end class 188