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