1<?php 2/** 3 * Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff. 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 * Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff. 18 * 19 * Verifies that there is a space between each condition of for loops. 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 Squiz_Sniffs_ControlStructures_ForLoopDeclarationSniff implements PHP_CodeSniffer_Sniff 31{ 32 33 /** 34 * How many spaces should follow the opening bracket. 35 * 36 * @var int 37 */ 38 public $requiredSpacesAfterOpen = 0; 39 40 /** 41 * How many spaces should precede the closing bracket. 42 * 43 * @var int 44 */ 45 public $requiredSpacesBeforeClose = 0; 46 47 /** 48 * A list of tokenizers this sniff supports. 49 * 50 * @var array 51 */ 52 public $supportedTokenizers = array( 53 'PHP', 54 'JS', 55 ); 56 57 58 /** 59 * Returns an array of tokens this test wants to listen for. 60 * 61 * @return array 62 */ 63 public function register() 64 { 65 return array(T_FOR); 66 67 }//end register() 68 69 70 /** 71 * Processes this test, when one of its tokens is encountered. 72 * 73 * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. 74 * @param int $stackPtr The position of the current token in the 75 * stack passed in $tokens. 76 * 77 * @return void 78 */ 79 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 80 { 81 $this->requiredSpacesAfterOpen = (int) $this->requiredSpacesAfterOpen; 82 $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose; 83 $tokens = $phpcsFile->getTokens(); 84 85 $openingBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr); 86 if ($openingBracket === false) { 87 $error = 'Possible parse error: no opening parenthesis for FOR keyword'; 88 $phpcsFile->addWarning($error, $stackPtr, 'NoOpenBracket'); 89 return; 90 } 91 92 $closingBracket = $tokens[$openingBracket]['parenthesis_closer']; 93 94 if ($this->requiredSpacesAfterOpen === 0 && $tokens[($openingBracket + 1)]['code'] === T_WHITESPACE) { 95 $error = 'Space found after opening bracket of FOR loop'; 96 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterOpen'); 97 if ($fix === true) { 98 $phpcsFile->fixer->replaceToken(($openingBracket + 1), ''); 99 } 100 } else if ($this->requiredSpacesAfterOpen > 0) { 101 $spaceAfterOpen = 0; 102 if ($tokens[($openingBracket + 1)]['code'] === T_WHITESPACE) { 103 $spaceAfterOpen = strlen($tokens[($openingBracket + 1)]['content']); 104 } 105 106 if ($spaceAfterOpen !== $this->requiredSpacesAfterOpen) { 107 $error = 'Expected %s spaces after opening bracket; %s found'; 108 $data = array( 109 $this->requiredSpacesAfterOpen, 110 $spaceAfterOpen, 111 ); 112 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterOpen', $data); 113 if ($fix === true) { 114 $padding = str_repeat(' ', $this->requiredSpacesAfterOpen); 115 if ($spaceAfterOpen === 0) { 116 $phpcsFile->fixer->addContent($openingBracket, $padding); 117 } else { 118 $phpcsFile->fixer->replaceToken(($openingBracket + 1), $padding); 119 } 120 } 121 } 122 }//end if 123 124 if ($this->requiredSpacesBeforeClose === 0 && $tokens[($closingBracket - 1)]['code'] === T_WHITESPACE) { 125 $error = 'Space found before closing bracket of FOR loop'; 126 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBeforeClose'); 127 if ($fix === true) { 128 $phpcsFile->fixer->replaceToken(($closingBracket - 1), ''); 129 } 130 } else if ($this->requiredSpacesBeforeClose > 0) { 131 $spaceBeforeClose = 0; 132 if ($tokens[($closingBracket - 1)]['code'] === T_WHITESPACE) { 133 $spaceBeforeClose = strlen($tokens[($closingBracket - 1)]['content']); 134 } 135 136 if ($this->requiredSpacesBeforeClose !== $spaceBeforeClose) { 137 $error = 'Expected %s spaces before closing bracket; %s found'; 138 $data = array( 139 $this->requiredSpacesBeforeClose, 140 $spaceBeforeClose, 141 ); 142 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBeforeClose', $data); 143 if ($fix === true) { 144 $padding = str_repeat(' ', $this->requiredSpacesBeforeClose); 145 if ($spaceBeforeClose === 0) { 146 $phpcsFile->fixer->addContentBefore($closingBracket, $padding); 147 } else { 148 $phpcsFile->fixer->replaceToken(($closingBracket - 1), $padding); 149 } 150 } 151 } 152 }//end if 153 154 $firstSemicolon = $phpcsFile->findNext(T_SEMICOLON, $openingBracket, $closingBracket); 155 156 // Check whitespace around each of the tokens. 157 if ($firstSemicolon !== false) { 158 if ($tokens[($firstSemicolon - 1)]['code'] === T_WHITESPACE) { 159 $error = 'Space found before first semicolon of FOR loop'; 160 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBeforeFirst'); 161 if ($fix === true) { 162 $phpcsFile->fixer->replaceToken(($firstSemicolon - 1), ''); 163 } 164 } 165 166 if ($tokens[($firstSemicolon + 1)]['code'] !== T_WHITESPACE 167 && $tokens[($firstSemicolon + 1)]['code'] !== T_SEMICOLON 168 ) { 169 $error = 'Expected 1 space after first semicolon of FOR loop; 0 found'; 170 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpaceAfterFirst'); 171 if ($fix === true) { 172 $phpcsFile->fixer->addContent($firstSemicolon, ' '); 173 } 174 } else { 175 if (strlen($tokens[($firstSemicolon + 1)]['content']) !== 1) { 176 $spaces = strlen($tokens[($firstSemicolon + 1)]['content']); 177 $error = 'Expected 1 space after first semicolon of FOR loop; %s found'; 178 $data = array($spaces); 179 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterFirst', $data); 180 if ($fix === true) { 181 $phpcsFile->fixer->replaceToken(($firstSemicolon + 1), ' '); 182 } 183 } 184 } 185 186 $secondSemicolon = $phpcsFile->findNext(T_SEMICOLON, ($firstSemicolon + 1)); 187 188 if ($secondSemicolon !== false) { 189 if ($tokens[($secondSemicolon - 1)]['code'] === T_WHITESPACE 190 && $tokens[($firstSemicolon + 1)]['code'] !== T_SEMICOLON 191 ) { 192 $error = 'Space found before second semicolon of FOR loop'; 193 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBeforeSecond'); 194 if ($fix === true) { 195 $phpcsFile->fixer->replaceToken(($secondSemicolon - 1), ''); 196 } 197 } 198 199 if (($secondSemicolon + 1) !== $closingBracket 200 && $tokens[($secondSemicolon + 1)]['code'] !== T_WHITESPACE 201 ) { 202 $error = 'Expected 1 space after second semicolon of FOR loop; 0 found'; 203 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpaceAfterSecond'); 204 if ($fix === true) { 205 $phpcsFile->fixer->addContent($secondSemicolon, ' '); 206 } 207 } else { 208 if (strlen($tokens[($secondSemicolon + 1)]['content']) !== 1) { 209 $spaces = strlen($tokens[($secondSemicolon + 1)]['content']); 210 $data = array($spaces); 211 if (($secondSemicolon + 2) === $closingBracket) { 212 $error = 'Expected no space after second semicolon of FOR loop; %s found'; 213 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterSecondNoThird', $data); 214 if ($fix === true) { 215 $phpcsFile->fixer->replaceToken(($secondSemicolon + 1), ''); 216 } 217 } else { 218 $error = 'Expected 1 space after second semicolon of FOR loop; %s found'; 219 $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterSecond', $data); 220 if ($fix === true) { 221 $phpcsFile->fixer->replaceToken(($secondSemicolon + 1), ' '); 222 } 223 } 224 } 225 }//end if 226 }//end if 227 }//end if 228 229 }//end process() 230 231 232}//end class 233