PHP_CodeSniffer
[ class tree: PHP_CodeSniffer ] [ index: PHP_CodeSniffer ] [ all elements ]

Source for file ComparisonOperatorUsageSniff.php

Documentation is available at ComparisonOperatorUsageSniff.php

  1. <?php
  2. /**
  3.  * A Sniff to enforce the use of IDENTICAL type operators rather than EQUAL operators.
  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.  
  10. namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\Operators;
  11.  
  12. use PHP_CodeSniffer\Sniffs\Sniff;
  13. use PHP_CodeSniffer\Files\File;
  14. use PHP_CodeSniffer\Util\Tokens;
  15.  
  16. class ComparisonOperatorUsageSniff implements Sniff
  17. {
  18.  
  19.     /**
  20.      * A list of tokenizers this sniff supports.
  21.      *
  22.      * @var array 
  23.      */
  24.     public $supportedTokenizers = array(
  25.                                    'PHP',
  26.                                    'JS',
  27.                                   );
  28.  
  29.     /**
  30.      * A list of valid comparison operators.
  31.      *
  32.      * @var array 
  33.      */
  34.     private static $validOps = array(
  35.                                 T_IS_IDENTICAL,
  36.                                 T_IS_NOT_IDENTICAL,
  37.                                 T_LESS_THAN,
  38.                                 T_GREATER_THAN,
  39.                                 T_IS_GREATER_OR_EQUAL,
  40.                                 T_IS_SMALLER_OR_EQUAL,
  41.                                 T_INSTANCEOF,
  42.                                );
  43.  
  44.     /**
  45.      * A list of invalid operators with their alternatives.
  46.      *
  47.      * @var array<int, string>
  48.      */
  49.     private static $invalidOps = array(
  50.                                   'PHP' => array(
  51.                                             T_IS_EQUAL     => '===',
  52.                                             T_IS_NOT_EQUAL => '!==',
  53.                                             T_BOOLEAN_NOT  => '=== FALSE',
  54.                                            ),
  55.                                   'JS'  => array(
  56.                                             T_IS_EQUAL     => '===',
  57.                                             T_IS_NOT_EQUAL => '!==',
  58.                                            ),
  59.                                  );
  60.  
  61.  
  62.     /**
  63.      * Registers the token types that this sniff wishes to listen to.
  64.      *
  65.      * @return array 
  66.      */
  67.     public function register()
  68.     {
  69.         return array(
  70.                 T_IF,
  71.                 T_ELSEIF,
  72.                 T_INLINE_THEN,
  73.                 T_WHILE,
  74.                 T_FOR,
  75.                );
  76.  
  77.     }//end register()
  78.  
  79.  
  80.     /**
  81.      * Process the tokens that this sniff is listening for.
  82.      *
  83.      * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where the token was found.
  84.      * @param int                         $stackPtr  The position in the stack where the token
  85.      *                                                was found.
  86.      *
  87.      * @return void 
  88.      */
  89.     public function process(File $phpcsFile$stackPtr)
  90.     {
  91.         $tokens    $phpcsFile->getTokens();
  92.         $tokenizer $phpcsFile->tokenizerType;
  93.  
  94.         if ($tokens[$stackPtr]['code'=== T_INLINE_THEN{
  95.             $end $phpcsFile->findPrevious(Tokens::$emptyTokens($stackPtr - 1)nulltrue);
  96.             if ($tokens[$end]['code'!== T_CLOSE_PARENTHESIS{
  97.                 // This inline IF statement does not have its condition
  98.                 // bracketed, so we need to guess where it starts.
  99.                 for ($i ($end - 1)$i >= 0; $i--{
  100.                     if ($tokens[$i]['code'=== T_SEMICOLON{
  101.                         // Stop here as we assume it is the end
  102.                         // of the previous statement.
  103.                         break;
  104.                     else if ($tokens[$i]['code'=== T_OPEN_TAG{
  105.                         // Stop here as this is the start of the file.
  106.                         break;
  107.                     else if ($tokens[$i]['code'=== T_CLOSE_CURLY_BRACKET{
  108.                         // Stop if this is the closing brace of
  109.                         // a code block.
  110.                         if (isset($tokens[$i]['scope_opener']=== true{
  111.                             break;
  112.                         }
  113.                     else if ($tokens[$i]['code'=== T_OPEN_CURLY_BRACKET{
  114.                         // Stop if this is the opening brace of
  115.                         // a code block.
  116.                         if (isset($tokens[$i]['scope_closer']=== true{
  117.                             break;
  118.                         }
  119.                     }
  120.                 }//end for
  121.  
  122.                 $start $phpcsFile->findNext(Tokens::$emptyTokens($i + 1)nulltrue);
  123.             else {
  124.                 if (isset($tokens[$end]['parenthesis_opener']=== false{
  125.                     return;
  126.                 }
  127.  
  128.                 $start $tokens[$end]['parenthesis_opener'];
  129.             }//end if
  130.         else if ($tokens[$stackPtr]['code'=== T_FOR{
  131.             if (isset($tokens[$stackPtr]['parenthesis_opener']=== false{
  132.                 return;
  133.             }
  134.  
  135.             $openingBracket $tokens[$stackPtr]['parenthesis_opener'];
  136.             $closingBracket $tokens[$stackPtr]['parenthesis_closer'];
  137.  
  138.             $start $phpcsFile->findNext(T_SEMICOLON$openingBracket$closingBracket);
  139.             $end   $phpcsFile->findNext(T_SEMICOLON($start + 1)$closingBracket);
  140.             if ($start === false || $end === false{
  141.                 return;
  142.             }
  143.         else {
  144.             if (isset($tokens[$stackPtr]['parenthesis_opener']=== false{
  145.                 return;
  146.             }
  147.  
  148.             $start $tokens[$stackPtr]['parenthesis_opener'];
  149.             $end   $tokens[$stackPtr]['parenthesis_closer'];
  150.         }//end if
  151.  
  152.         $requiredOps = 0;
  153.         $foundOps    = 0;
  154.         $foundBools  = 0;
  155.  
  156.         for ($i $start$i <= $end$i++{
  157.             $type $tokens[$i]['code'];
  158.             if (in_array($typearray_keys(self::$invalidOps[$tokenizer])) === true{
  159.                 $error 'Operator %s prohibited; use %s instead';
  160.                 $data  = array(
  161.                           $tokens[$i]['content'],
  162.                           self::$invalidOps[$tokenizer][$type],
  163.                          );
  164.                 $phpcsFile->addError($error$i'NotAllowed'$data);
  165.                 $foundOps++;
  166.             else if (in_array($typeself::$validOps=== true{
  167.                 $foundOps++;
  168.             }
  169.  
  170.             if ($tokens[$i]['code'=== T_TRUE || $tokens[$i]['code'=== T_FALSE{
  171.                 $foundBools++;
  172.             }
  173.  
  174.             if ($phpcsFile->tokenizerType !== 'JS'
  175.                 && ($tokens[$i]['code'=== T_BOOLEAN_AND
  176.                 || $tokens[$i]['code'=== T_BOOLEAN_OR)
  177.             {
  178.                 $requiredOps++;
  179.  
  180.                 // When the instanceof operator is used with another operator
  181.                 // like ===, you can get more ops than are required.
  182.                 if ($foundOps $requiredOps{
  183.                     $foundOps $requiredOps;
  184.                 }
  185.  
  186.                 // If we get to here and we have not found the right number of
  187.                 // comparison operators, then we must have had an implicit
  188.                 // true operation i.e., if ($a) instead of the required
  189.                 // if ($a === true), so let's add an error.
  190.                 if ($requiredOps !== $foundOps{
  191.                     $error 'Implicit true comparisons prohibited; use === TRUE instead';
  192.                     $phpcsFile->addError($error$stackPtr'ImplicitTrue');
  193.                     $foundOps++;
  194.                 }
  195.             }
  196.         }//end for
  197.  
  198.         $requiredOps++;
  199.  
  200.         if ($phpcsFile->tokenizerType !== 'JS'
  201.             && $foundOps $requiredOps
  202.             && ($requiredOps !== $foundBools)
  203.         {
  204.             $error 'Implicit true comparisons prohibited; use === TRUE instead';
  205.             $phpcsFile->addError($error$stackPtr'ImplicitTrue');
  206.         }
  207.  
  208.     }//end process()
  209.  
  210.  
  211. }//end class

Documentation generated on Mon, 11 Mar 2019 15:27:18 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.