1<?php 2/** 3 * Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 12 * @link http://pear.php.net/package/PHP_CodeSniffer 13 */ 14 15/** 16 * Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff. 17 * 18 * Bans the use of size-based functions in loop conditions. 19 * 20 * @category PHP 21 * @package PHP_CodeSniffer 22 * @author Greg Sherwood <gsherwood@squiz.net> 23 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 24 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 25 * @version Release: @package_version@ 26 * @link http://pear.php.net/package/PHP_CodeSniffer 27 */ 28class Squiz_Sniffs_PHP_DisallowSizeFunctionsInLoopsSniff implements PHP_CodeSniffer_Sniff 29{ 30 31 /** 32 * A list of tokenizers this sniff supports. 33 * 34 * @var array 35 */ 36 public $supportedTokenizers = array( 37 'PHP', 38 'JS', 39 ); 40 41 /** 42 * An array of functions we don't want in the condition of loops. 43 * 44 * @return array 45 */ 46 protected $forbiddenFunctions = array( 47 'PHP' => array( 48 'sizeof' => true, 49 'strlen' => true, 50 'count' => true, 51 ), 52 'JS' => array('length' => true), 53 ); 54 55 56 /** 57 * Returns an array of tokens this test wants to listen for. 58 * 59 * @return array 60 */ 61 public function register() 62 { 63 return array( 64 T_WHILE, 65 T_FOR, 66 ); 67 68 }//end register() 69 70 71 /** 72 * Processes this test, when one of its tokens is encountered. 73 * 74 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 75 * @param int $stackPtr The position of the current token 76 * in the stack passed in $tokens. 77 * 78 * @return void 79 */ 80 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 81 { 82 $tokens = $phpcsFile->getTokens(); 83 $tokenizer = $phpcsFile->tokenizerType; 84 $openBracket = $tokens[$stackPtr]['parenthesis_opener']; 85 $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; 86 87 if ($tokens[$stackPtr]['code'] === T_FOR) { 88 // We only want to check the condition in FOR loops. 89 $start = $phpcsFile->findNext(T_SEMICOLON, ($openBracket + 1)); 90 $end = $phpcsFile->findPrevious(T_SEMICOLON, ($closeBracket - 1)); 91 } else { 92 $start = $openBracket; 93 $end = $closeBracket; 94 } 95 96 for ($i = ($start + 1); $i < $end; $i++) { 97 if ($tokens[$i]['code'] === T_STRING 98 && isset($this->forbiddenFunctions[$tokenizer][$tokens[$i]['content']]) === true 99 ) { 100 $functionName = $tokens[$i]['content']; 101 if ($tokenizer === 'JS') { 102 // Needs to be in the form object.function to be valid. 103 $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($i - 1), null, true); 104 if ($prev === false || $tokens[$prev]['code'] !== T_OBJECT_OPERATOR) { 105 continue; 106 } 107 108 $functionName = 'object.'.$functionName; 109 } else { 110 // Make sure it isn't a member var. 111 if ($tokens[($i - 1)]['code'] === T_OBJECT_OPERATOR) { 112 continue; 113 } 114 115 $functionName .= '()'; 116 } 117 118 $error = 'The use of %s inside a loop condition is not allowed; assign the return value to a variable and use the variable in the loop condition instead'; 119 $data = array($functionName); 120 $phpcsFile->addError($error, $i, 'Found', $data); 121 }//end if 122 }//end for 123 124 }//end process() 125 126 127}//end class 128