• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHPCSStandards / PHP_CodeSniffer / 17663621563

12 Sep 2025 03:25AM UTC coverage: 78.786%. Remained the same
17663621563

push

github

web-flow
Merge pull request #1243 from PHPCSStandards/phpcs-4.x/feature/155-normalize-some-code-style-rules-5

CS: normalize code style rules [5]

294 of 308 new or added lines in 191 files covered. (95.45%)

2354 existing lines in 130 files now uncovered.

19732 of 25045 relevant lines covered (78.79%)

96.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.68
/src/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php
1
<?php
2
/**
3
 * Verifies that there is a space between each condition of for loops.
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/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
8
 */
9

10
namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\ControlStructures;
11

12
use PHP_CodeSniffer\Files\File;
13
use PHP_CodeSniffer\Sniffs\Sniff;
14
use PHP_CodeSniffer\Util\Tokens;
15

16
class ForLoopDeclarationSniff implements Sniff
17
{
18

19
    /**
20
     * How many spaces should follow the opening bracket.
21
     *
22
     * @var integer
23
     */
24
    public $requiredSpacesAfterOpen = 0;
25

26
    /**
27
     * How many spaces should precede the closing bracket.
28
     *
29
     * @var integer
30
     */
31
    public $requiredSpacesBeforeClose = 0;
32

33
    /**
34
     * Allow newlines instead of spaces.
35
     *
36
     * @var boolean
37
     */
38
    public $ignoreNewlines = false;
39

40

41
    /**
42
     * Returns an array of tokens this test wants to listen for.
43
     *
44
     * @return array<int|string>
45
     */
46
    public function register()
3✔
47
    {
48
        return [T_FOR];
3✔
49
    }
50

51

52
    /**
53
     * Processes this test, when one of its tokens is encountered.
54
     *
55
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
56
     * @param int                         $stackPtr  The position of the current token in the
57
     *                                               stack passed in $tokens.
58
     *
59
     * @return void
60
     */
61
    public function process(File $phpcsFile, int $stackPtr)
3✔
62
    {
63
        $this->requiredSpacesAfterOpen   = (int) $this->requiredSpacesAfterOpen;
3✔
64
        $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose;
3✔
65
        $tokens = $phpcsFile->getTokens();
3✔
66

67
        $openingBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr);
3✔
68
        if ($openingBracket === false || isset($tokens[$openingBracket]['parenthesis_closer']) === false) {
3✔
69
            // Parse error or live coding.
70
            return;
3✔
71
        }
72

73
        $closingBracket = $tokens[$openingBracket]['parenthesis_closer'];
3✔
74

75
        if ($this->requiredSpacesAfterOpen === 0
3✔
76
            && $tokens[($openingBracket + 1)]['code'] === T_WHITESPACE
3✔
77
        ) {
78
            $nextNonWhiteSpace = $phpcsFile->findNext(T_WHITESPACE, ($openingBracket + 1), $closingBracket, true);
3✔
79
            if ($this->ignoreNewlines === false
3✔
80
                || $tokens[$nextNonWhiteSpace]['line'] === $tokens[$openingBracket]['line']
3✔
81
            ) {
82
                $error = 'Whitespace found after opening bracket of FOR loop';
3✔
83
                $fix   = $phpcsFile->addFixableError($error, $openingBracket, 'SpacingAfterOpen');
3✔
84
                if ($fix === true) {
3✔
85
                    $phpcsFile->fixer->beginChangeset();
3✔
86
                    for ($i = ($openingBracket + 1); $i < $closingBracket; $i++) {
3✔
87
                        if ($tokens[$i]['code'] !== T_WHITESPACE) {
3✔
88
                            break;
3✔
89
                        }
90

91
                        $phpcsFile->fixer->replaceToken($i, '');
3✔
92
                    }
93

94
                    $phpcsFile->fixer->endChangeset();
3✔
95
                }
96
            }
97
        } elseif ($this->requiredSpacesAfterOpen > 0) {
3✔
98
            $nextNonWhiteSpace = $phpcsFile->findNext(T_WHITESPACE, ($openingBracket + 1), $closingBracket, true);
3✔
99
            $spaceAfterOpen    = 0;
3✔
100
            if ($tokens[$openingBracket]['line'] !== $tokens[$nextNonWhiteSpace]['line']) {
3✔
101
                $spaceAfterOpen = 'newline';
3✔
102
            } elseif ($tokens[($openingBracket + 1)]['code'] === T_WHITESPACE) {
3✔
103
                $spaceAfterOpen = $tokens[($openingBracket + 1)]['length'];
3✔
104
            }
105

106
            if ($spaceAfterOpen !== $this->requiredSpacesAfterOpen
3✔
107
                && ($this->ignoreNewlines === false
3✔
108
                || $spaceAfterOpen !== 'newline')
3✔
109
            ) {
110
                $error = 'Expected %s spaces after opening bracket; %s found';
3✔
111
                $data  = [
2✔
112
                    $this->requiredSpacesAfterOpen,
3✔
113
                    $spaceAfterOpen,
3✔
114
                ];
2✔
115
                $fix   = $phpcsFile->addFixableError($error, $openingBracket, 'SpacingAfterOpen', $data);
3✔
116
                if ($fix === true) {
3✔
117
                    $padding = str_repeat(' ', $this->requiredSpacesAfterOpen);
3✔
118
                    if ($spaceAfterOpen === 0) {
3✔
119
                        $phpcsFile->fixer->addContent($openingBracket, $padding);
3✔
120
                    } else {
121
                        $phpcsFile->fixer->beginChangeset();
3✔
122
                        $phpcsFile->fixer->replaceToken(($openingBracket + 1), $padding);
3✔
123
                        for ($i = ($openingBracket + 2); $i < $nextNonWhiteSpace; $i++) {
3✔
124
                            $phpcsFile->fixer->replaceToken($i, '');
3✔
125
                        }
126

127
                        $phpcsFile->fixer->endChangeset();
3✔
128
                    }
129
                }
130
            }//end if
131
        }//end if
132

133
        $prevNonWhiteSpace  = $phpcsFile->findPrevious(T_WHITESPACE, ($closingBracket - 1), $openingBracket, true);
3✔
134
        $beforeClosefixable = true;
3✔
135
        if ($tokens[$prevNonWhiteSpace]['line'] !== $tokens[$closingBracket]['line']
3✔
136
            && isset(Tokens::EMPTY_TOKENS[$tokens[$prevNonWhiteSpace]['code']]) === true
3✔
137
        ) {
138
            $beforeClosefixable = false;
3✔
139
        }
140

141
        if ($this->requiredSpacesBeforeClose === 0
3✔
142
            && $tokens[($closingBracket - 1)]['code'] === T_WHITESPACE
3✔
143
            && ($this->ignoreNewlines === false
3✔
144
            || $tokens[$prevNonWhiteSpace]['line'] === $tokens[$closingBracket]['line'])
3✔
145
        ) {
146
            $error = 'Whitespace found before closing bracket of FOR loop';
3✔
147

148
            if ($beforeClosefixable === false) {
3✔
149
                $phpcsFile->addError($error, $closingBracket, 'SpacingBeforeClose');
3✔
150
            } else {
151
                $fix = $phpcsFile->addFixableError($error, $closingBracket, 'SpacingBeforeClose');
3✔
152
                if ($fix === true) {
3✔
153
                    $phpcsFile->fixer->beginChangeset();
3✔
154
                    for ($i = ($closingBracket - 1); $i > $openingBracket; $i--) {
3✔
155
                        if ($tokens[$i]['code'] !== T_WHITESPACE) {
3✔
156
                            break;
3✔
157
                        }
158

159
                        $phpcsFile->fixer->replaceToken($i, '');
3✔
160
                    }
161

162
                    $phpcsFile->fixer->endChangeset();
3✔
163
                }
164
            }
165
        } elseif ($this->requiredSpacesBeforeClose > 0) {
3✔
166
            $spaceBeforeClose = 0;
3✔
167
            if ($tokens[$closingBracket]['line'] !== $tokens[$prevNonWhiteSpace]['line']) {
3✔
168
                $spaceBeforeClose = 'newline';
3✔
169
            } elseif ($tokens[($closingBracket - 1)]['code'] === T_WHITESPACE) {
3✔
170
                $spaceBeforeClose = $tokens[($closingBracket - 1)]['length'];
3✔
171
            }
172

173
            if ($this->requiredSpacesBeforeClose !== $spaceBeforeClose
3✔
174
                && ($this->ignoreNewlines === false
3✔
175
                || $spaceBeforeClose !== 'newline')
3✔
176
            ) {
177
                $error = 'Expected %s spaces before closing bracket; %s found';
3✔
178
                $data  = [
2✔
179
                    $this->requiredSpacesBeforeClose,
3✔
180
                    $spaceBeforeClose,
3✔
181
                ];
2✔
182

183
                if ($beforeClosefixable === false) {
3✔
UNCOV
184
                    $phpcsFile->addError($error, $closingBracket, 'SpacingBeforeClose', $data);
×
185
                } else {
186
                    $fix = $phpcsFile->addFixableError($error, $closingBracket, 'SpacingBeforeClose', $data);
3✔
187
                    if ($fix === true) {
3✔
188
                        $padding = str_repeat(' ', $this->requiredSpacesBeforeClose);
3✔
189
                        if ($spaceBeforeClose === 0) {
3✔
190
                            $phpcsFile->fixer->addContentBefore($closingBracket, $padding);
3✔
191
                        } else {
192
                            $phpcsFile->fixer->beginChangeset();
3✔
193
                            $phpcsFile->fixer->replaceToken(($closingBracket - 1), $padding);
3✔
194
                            for ($i = ($closingBracket - 2); $i > $prevNonWhiteSpace; $i--) {
3✔
195
                                $phpcsFile->fixer->replaceToken($i, '');
3✔
196
                            }
197

198
                            $phpcsFile->fixer->endChangeset();
3✔
199
                        }
200
                    }
201
                }
202
            }//end if
203
        }//end if
204

205
        /*
206
         * Check whitespace around each of the semicolon tokens.
207
         */
208

209
        $semicolonCount     = 0;
3✔
210
        $semicolon          = $openingBracket;
3✔
211
        $targetNestinglevel = 0;
3✔
212
        if (isset($tokens[$openingBracket]['conditions']) === true) {
3✔
213
            $targetNestinglevel = count($tokens[$openingBracket]['conditions']);
3✔
214
        }
215

216
        do {
217
            $semicolon = $phpcsFile->findNext(T_SEMICOLON, ($semicolon + 1), $closingBracket);
3✔
218
            if ($semicolon === false) {
3✔
UNCOV
219
                break;
×
220
            }
221

222
            if (isset($tokens[$semicolon]['conditions']) === true
3✔
223
                && count($tokens[$semicolon]['conditions']) > $targetNestinglevel
3✔
224
            ) {
225
                // Semicolon doesn't belong to the for().
226
                continue;
3✔
227
            }
228

229
            ++$semicolonCount;
3✔
230

231
            $humanReadableCount = 'first';
3✔
232
            if ($semicolonCount !== 1) {
3✔
233
                $humanReadableCount = 'second';
3✔
234
            }
235

236
            $humanReadableCode = ucfirst($humanReadableCount);
3✔
237
            $data = [$humanReadableCount];
3✔
238

239
            // Only examine the space before the first semicolon if the first expression is not empty.
240
            // If it *is* empty, leave it up to the `SpacingAfterOpen` logic.
241
            $prevNonWhiteSpace = $phpcsFile->findPrevious(T_WHITESPACE, ($semicolon - 1), $openingBracket, true);
3✔
242
            if ($semicolonCount !== 1 || $prevNonWhiteSpace !== $openingBracket) {
3✔
243
                if ($tokens[($semicolon - 1)]['code'] === T_WHITESPACE) {
3✔
244
                    $error     = 'Whitespace found before %s semicolon of FOR loop';
3✔
245
                    $errorCode = 'SpacingBefore' . $humanReadableCode;
3✔
246
                    $fix       = $phpcsFile->addFixableError($error, $semicolon, $errorCode, $data);
3✔
247
                    if ($fix === true) {
3✔
248
                        $phpcsFile->fixer->beginChangeset();
3✔
249
                        for ($i = ($semicolon - 1); $i > $prevNonWhiteSpace; $i--) {
3✔
250
                            $phpcsFile->fixer->replaceToken($i, '');
3✔
251
                        }
252

253
                        $phpcsFile->fixer->endChangeset();
3✔
254
                    }
255
                }
256
            }
257

258
            // Only examine the space after the second semicolon if the last expression is not empty.
259
            // If it *is* empty, leave it up to the `SpacingBeforeClose` logic.
260
            $nextNonWhiteSpace = $phpcsFile->findNext(T_WHITESPACE, ($semicolon + 1), ($closingBracket + 1), true);
3✔
261
            if ($semicolonCount !== 2 || $nextNonWhiteSpace !== $closingBracket) {
3✔
262
                if ($tokens[($semicolon + 1)]['code'] !== T_WHITESPACE
3✔
263
                    && $tokens[($semicolon + 1)]['code'] !== T_SEMICOLON
3✔
264
                ) {
265
                    $error     = 'Expected 1 space after %s semicolon of FOR loop; 0 found';
3✔
266
                    $errorCode = 'NoSpaceAfter' . $humanReadableCode;
3✔
267
                    $fix       = $phpcsFile->addFixableError($error, $semicolon, $errorCode, $data);
3✔
268
                    if ($fix === true) {
3✔
269
                        $phpcsFile->fixer->addContent($semicolon, ' ');
3✔
270
                    }
271
                } elseif ($tokens[($semicolon + 1)]['code'] === T_WHITESPACE
3✔
272
                    && $tokens[$nextNonWhiteSpace]['code'] !== T_SEMICOLON
3✔
273
                ) {
274
                    $spaces = $tokens[($semicolon + 1)]['length'];
3✔
275
                    if ($tokens[$semicolon]['line'] !== $tokens[$nextNonWhiteSpace]['line']) {
3✔
276
                        $spaces = 'newline';
3✔
277
                    }
278

279
                    if ($spaces !== 1
3✔
280
                        && ($this->ignoreNewlines === false
3✔
281
                        || $spaces !== 'newline')
3✔
282
                    ) {
283
                        $error     = 'Expected 1 space after %s semicolon of FOR loop; %s found';
3✔
284
                        $errorCode = 'SpacingAfter' . $humanReadableCode;
3✔
285
                        $data[]    = $spaces;
3✔
286
                        $fix       = $phpcsFile->addFixableError($error, $semicolon, $errorCode, $data);
3✔
287
                        if ($fix === true) {
3✔
288
                            $phpcsFile->fixer->beginChangeset();
3✔
289
                            $phpcsFile->fixer->replaceToken(($semicolon + 1), ' ');
3✔
290
                            for ($i = ($semicolon + 2); $i < $nextNonWhiteSpace; $i++) {
3✔
291
                                $phpcsFile->fixer->replaceToken($i, '');
3✔
292
                            }
293

294
                            $phpcsFile->fixer->endChangeset();
3✔
295
                        }
296
                    }
297
                }//end if
298
            }//end if
299
        } while ($semicolonCount < 2);
3✔
300
    }
1✔
301
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc