/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php

https://github.com/squizlabs/PHP_CodeSniffer · PHP · 196 lines · 120 code · 28 blank · 48 comment · 29 complexity · 131fb9a8b2d0643c649ba8bc52e63db2 MD5 · raw file

  1. <?php
  2. /**
  3. * Checks the naming of variables and member variables.
  4. *
  5. * @author Greg Sherwood <gsherwood@squiz.net>
  6. * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
  7. * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  8. */
  9. namespace PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions;
  10. use PHP_CodeSniffer\Sniffs\AbstractVariableSniff;
  11. use PHP_CodeSniffer\Util\Common;
  12. use PHP_CodeSniffer\Files\File;
  13. use PHP_CodeSniffer\Util\Tokens;
  14. class ValidVariableNameSniff extends AbstractVariableSniff
  15. {
  16. /**
  17. * Processes this test, when one of its tokens is encountered.
  18. *
  19. * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  20. * @param int $stackPtr The position of the current token in the
  21. * stack passed in $tokens.
  22. *
  23. * @return void
  24. */
  25. protected function processVariable(File $phpcsFile, $stackPtr)
  26. {
  27. $tokens = $phpcsFile->getTokens();
  28. $varName = ltrim($tokens[$stackPtr]['content'], '$');
  29. // If it's a php reserved var, then its ok.
  30. if (isset($this->phpReservedVars[$varName]) === true) {
  31. return;
  32. }
  33. $objOperator = $phpcsFile->findNext([T_WHITESPACE], ($stackPtr + 1), null, true);
  34. if ($tokens[$objOperator]['code'] === T_OBJECT_OPERATOR
  35. || $tokens[$objOperator]['code'] === T_NULLSAFE_OBJECT_OPERATOR
  36. ) {
  37. // Check to see if we are using a variable from an object.
  38. $var = $phpcsFile->findNext([T_WHITESPACE], ($objOperator + 1), null, true);
  39. if ($tokens[$var]['code'] === T_STRING) {
  40. // Either a var name or a function call, so check for bracket.
  41. $bracket = $phpcsFile->findNext([T_WHITESPACE], ($var + 1), null, true);
  42. if ($tokens[$bracket]['code'] !== T_OPEN_PARENTHESIS) {
  43. $objVarName = $tokens[$var]['content'];
  44. // There is no way for us to know if the var is public or private,
  45. // so we have to ignore a leading underscore if there is one and just
  46. // check the main part of the variable name.
  47. $originalVarName = $objVarName;
  48. if (substr($objVarName, 0, 1) === '_') {
  49. $objVarName = substr($objVarName, 1);
  50. }
  51. if (Common::isCamelCaps($objVarName, false, true, false) === false) {
  52. $error = 'Variable "%s" is not in valid camel caps format';
  53. $data = [$originalVarName];
  54. $phpcsFile->addError($error, $var, 'NotCamelCaps', $data);
  55. } else if (preg_match('|\d|', $objVarName) === 1) {
  56. $warning = 'Variable "%s" contains numbers but this is discouraged';
  57. $data = [$originalVarName];
  58. $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data);
  59. }
  60. }//end if
  61. }//end if
  62. }//end if
  63. // There is no way for us to know if the var is public or private,
  64. // so we have to ignore a leading underscore if there is one and just
  65. // check the main part of the variable name.
  66. $originalVarName = $varName;
  67. if (substr($varName, 0, 1) === '_') {
  68. $objOperator = $phpcsFile->findPrevious([T_WHITESPACE], ($stackPtr - 1), null, true);
  69. if ($tokens[$objOperator]['code'] === T_DOUBLE_COLON) {
  70. // The variable lives within a class, and is referenced like
  71. // this: MyClass::$_variable, so we don't know its scope.
  72. $inClass = true;
  73. } else {
  74. $inClass = $phpcsFile->hasCondition($stackPtr, Tokens::$ooScopeTokens);
  75. }
  76. if ($inClass === true) {
  77. $varName = substr($varName, 1);
  78. }
  79. }
  80. if (Common::isCamelCaps($varName, false, true, false) === false) {
  81. $error = 'Variable "%s" is not in valid camel caps format';
  82. $data = [$originalVarName];
  83. $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data);
  84. } else if (preg_match('|\d|', $varName) === 1) {
  85. $warning = 'Variable "%s" contains numbers but this is discouraged';
  86. $data = [$originalVarName];
  87. $phpcsFile->addWarning($warning, $stackPtr, 'ContainsNumbers', $data);
  88. }
  89. }//end processVariable()
  90. /**
  91. * Processes class member variables.
  92. *
  93. * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  94. * @param int $stackPtr The position of the current token in the
  95. * stack passed in $tokens.
  96. *
  97. * @return void
  98. */
  99. protected function processMemberVar(File $phpcsFile, $stackPtr)
  100. {
  101. $tokens = $phpcsFile->getTokens();
  102. $varName = ltrim($tokens[$stackPtr]['content'], '$');
  103. $memberProps = $phpcsFile->getMemberProperties($stackPtr);
  104. if (empty($memberProps) === true) {
  105. // Exception encountered.
  106. return;
  107. }
  108. $public = ($memberProps['scope'] === 'public');
  109. if ($public === true) {
  110. if (substr($varName, 0, 1) === '_') {
  111. $error = 'Public member variable "%s" must not contain a leading underscore';
  112. $data = [$varName];
  113. $phpcsFile->addError($error, $stackPtr, 'PublicHasUnderscore', $data);
  114. }
  115. } else {
  116. if (substr($varName, 0, 1) !== '_') {
  117. $scope = ucfirst($memberProps['scope']);
  118. $error = '%s member variable "%s" must contain a leading underscore';
  119. $data = [
  120. $scope,
  121. $varName,
  122. ];
  123. $phpcsFile->addError($error, $stackPtr, 'PrivateNoUnderscore', $data);
  124. }
  125. }
  126. // Remove a potential underscore prefix for testing CamelCaps.
  127. $varName = ltrim($varName, '_');
  128. if (Common::isCamelCaps($varName, false, true, false) === false) {
  129. $error = 'Member variable "%s" is not in valid camel caps format';
  130. $data = [$varName];
  131. $phpcsFile->addError($error, $stackPtr, 'MemberVarNotCamelCaps', $data);
  132. } else if (preg_match('|\d|', $varName) === 1) {
  133. $warning = 'Member variable "%s" contains numbers but this is discouraged';
  134. $data = [$varName];
  135. $phpcsFile->addWarning($warning, $stackPtr, 'MemberVarContainsNumbers', $data);
  136. }
  137. }//end processMemberVar()
  138. /**
  139. * Processes the variable found within a double quoted string.
  140. *
  141. * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
  142. * @param int $stackPtr The position of the double quoted
  143. * string.
  144. *
  145. * @return void
  146. */
  147. protected function processVariableInString(File $phpcsFile, $stackPtr)
  148. {
  149. $tokens = $phpcsFile->getTokens();
  150. if (preg_match_all('|[^\\\]\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)|', $tokens[$stackPtr]['content'], $matches) !== 0) {
  151. foreach ($matches[1] as $varName) {
  152. // If it's a php reserved var, then its ok.
  153. if (isset($this->phpReservedVars[$varName]) === true) {
  154. continue;
  155. }
  156. if (Common::isCamelCaps($varName, false, true, false) === false) {
  157. $error = 'Variable "%s" is not in valid camel caps format';
  158. $data = [$varName];
  159. $phpcsFile->addError($error, $stackPtr, 'StringVarNotCamelCaps', $data);
  160. } else if (preg_match('|\d|', $varName) === 1) {
  161. $warning = 'Variable "%s" contains numbers but this is discouraged';
  162. $data = [$varName];
  163. $phpcsFile->addWarning($warning, $stackPtr, 'StringVarContainsNumbers', $data);
  164. }
  165. }//end foreach
  166. }//end if
  167. }//end processVariableInString()
  168. }//end class