/php/pear/PHP/CodeSniffer/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php

https://gitlab.com/trang1104/portable_project · PHP · 209 lines · 100 code · 21 blank · 88 comment · 24 complexity · 0ee1856791b6fb773fef77170408ab50 MD5 · raw file

  1. <?php
  2. /**
  3. * A Sniff to enforce the use of IDENTICAL type operators rather than EQUAL operators.
  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-2011 Squiz Pty Ltd (ABN 77 084 670 600)
  12. * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
  13. * @link http://pear.php.net/package/PHP_CodeSniffer
  14. */
  15. /**
  16. * A Sniff to enforce the use of IDENTICAL type operators rather than EQUAL operators.
  17. *
  18. * The use of === true is enforced over implicit true statements,
  19. * for example:
  20. *
  21. * <code>
  22. * if ($a)
  23. * {
  24. * ...
  25. * }
  26. * </code>
  27. *
  28. * should be:
  29. *
  30. * <code>
  31. * if ($a === true)
  32. * {
  33. * ...
  34. * }
  35. * </code>
  36. *
  37. * It also enforces the use of === false over ! operators.
  38. *
  39. * @category PHP
  40. * @package PHP_CodeSniffer
  41. * @author Greg Sherwood <gsherwood@squiz.net>
  42. * @author Marc McIntyre <mmcintyre@squiz.net>
  43. * @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600)
  44. * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
  45. * @version Release: 1.3.3
  46. * @link http://pear.php.net/package/PHP_CodeSniffer
  47. */
  48. class Squiz_Sniffs_Operators_ComparisonOperatorUsageSniff implements PHP_CodeSniffer_Sniff
  49. {
  50. /**
  51. * A list of tokenizers this sniff supports.
  52. *
  53. * @var array
  54. */
  55. public $supportedTokenizers = array(
  56. 'PHP',
  57. 'JS',
  58. );
  59. /**
  60. * A list of valid comparison operators.
  61. *
  62. * @var array
  63. */
  64. private static $_validOps = array(
  65. T_IS_IDENTICAL,
  66. T_IS_NOT_IDENTICAL,
  67. T_LESS_THAN,
  68. T_GREATER_THAN,
  69. T_IS_GREATER_OR_EQUAL,
  70. T_IS_SMALLER_OR_EQUAL,
  71. T_INSTANCEOF,
  72. );
  73. /**
  74. * A list of invalid operators with their alternatives.
  75. *
  76. * @var array(int => string)
  77. */
  78. private static $_invalidOps = array(
  79. 'PHP' => array(
  80. T_IS_EQUAL => '===',
  81. T_IS_NOT_EQUAL => '!==',
  82. T_BOOLEAN_NOT => '=== FALSE',
  83. ),
  84. 'JS' => array(
  85. T_IS_EQUAL => '===',
  86. T_IS_NOT_EQUAL => '!==',
  87. ),
  88. );
  89. /**
  90. * Registers the token types that this sniff wishes to listen to.
  91. *
  92. * @return array
  93. */
  94. public function register()
  95. {
  96. return array(
  97. T_IF,
  98. T_INLINE_THEN,
  99. );
  100. }//end register()
  101. /**
  102. * Process the tokens that this sniff is listening for.
  103. *
  104. * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found.
  105. * @param int $stackPtr The position in the stack where the token
  106. * was found.
  107. *
  108. * @return void
  109. */
  110. public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
  111. {
  112. $tokens = $phpcsFile->getTokens();
  113. $tokenizer = $phpcsFile->tokenizerType;
  114. if ($tokens[$stackPtr]['code'] === T_INLINE_THEN) {
  115. $end = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
  116. if ($tokens[$end]['code'] !== T_CLOSE_PARENTHESIS) {
  117. // This inline IF statement does not have its condition
  118. // bracketed, so we need to guess where it starts.
  119. for ($i = ($end - 1); $i >= 0; $i--) {
  120. if ($tokens[$i]['code'] === T_SEMICOLON) {
  121. // Stop here as we assume it is the end
  122. // of the previous statement.
  123. break;
  124. } else if ($tokens[$i]['code'] === T_OPEN_TAG) {
  125. // Stop here as this is the start of the file.
  126. break;
  127. } else if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET) {
  128. // Stop if this is the closing brace of
  129. // a code block.
  130. if (isset($tokens[$i]['scope_opener']) === true) {
  131. break;
  132. }
  133. } else if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) {
  134. // Stop if this is the opening brace of
  135. // a code block.
  136. if (isset($tokens[$i]['scope_closer']) === true) {
  137. break;
  138. }
  139. }
  140. }//end for
  141. $start = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($i + 1), null, true);
  142. } else {
  143. $start = $tokens[$end]['parenthesis_opener'];
  144. }
  145. } else {
  146. $start = $tokens[$stackPtr]['parenthesis_opener'];
  147. $end = $tokens[$stackPtr]['parenthesis_closer'];
  148. }
  149. $requiredOps = 0;
  150. $foundOps = 0;
  151. for ($i = $start; $i <= $end; $i++) {
  152. $type = $tokens[$i]['code'];
  153. if (in_array($type, array_keys(self::$_invalidOps[$tokenizer])) === true) {
  154. $error = 'Operator %s prohibited; use %s instead';
  155. $data = array(
  156. $tokens[$i]['content'],
  157. self::$_invalidOps[$tokenizer][$type],
  158. );
  159. $phpcsFile->addError($error, $i, 'NotAllowed', $data);
  160. $foundOps++;
  161. } else if (in_array($type, self::$_validOps) === true) {
  162. $foundOps++;
  163. }
  164. if ($phpcsFile->tokenizerType !== 'JS') {
  165. if ($tokens[$i]['code'] === T_BOOLEAN_AND || $tokens[$i]['code'] === T_BOOLEAN_OR) {
  166. $requiredOps++;
  167. // If we get to here and we have not found the right number of
  168. // comparison operators, then we must have had an implicit
  169. // true operation ie. if ($a) instead of the required
  170. // if ($a === true), so let's add an error.
  171. if ($requiredOps !== $foundOps) {
  172. $error = 'Implicit true comparisons prohibited; use === TRUE instead';
  173. $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue');
  174. $foundOps++;
  175. }
  176. }
  177. }//end if
  178. }//end for
  179. $requiredOps++;
  180. if ($phpcsFile->tokenizerType !== 'JS') {
  181. if ($foundOps < $requiredOps) {
  182. $error = 'Implicit true comparisons prohibited; use === TRUE instead';
  183. $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue');
  184. }
  185. }
  186. }//end process()
  187. }//end class
  188. ?>