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

PHPCSStandards / PHP_CodeSniffer / 10984063984

22 Sep 2024 08:12PM UTC coverage: 75.611% (+0.001%) from 75.61%
10984063984

Pull #620

github

web-flow
Merge 1f3ed7605 into 92c8ef543
Pull Request #620: Fix fixer conflict: `PSR12` / `Squiz.Functions.FunctionDeclarationArgumentSpacing`

13 of 14 new or added lines in 1 file covered. (92.86%)

6 existing lines in 1 file now uncovered.

23342 of 30871 relevant lines covered (75.61%)

61.81 hits per line

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

96.27
/src/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php
1
<?php
2
/**
3
 * Checks that arguments in function declarations are spaced correctly.
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\Functions;
11

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

16
class FunctionDeclarationArgumentSpacingSniff implements Sniff
17
{
18

19
    /**
20
     * How many spaces should surround the equals signs.
21
     *
22
     * @var integer
23
     */
24
    public $equalsSpacing = 0;
25

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

33
    /**
34
     * How many spaces should precede the closing bracket.
35
     *
36
     * @var integer
37
     */
38
    public $requiredSpacesBeforeClose = 0;
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 [
1✔
49
            T_FUNCTION,
3✔
50
            T_CLOSURE,
3✔
51
            T_FN,
3✔
52
        ];
2✔
53

54
    }//end register()
55

56

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

70
        if (isset($tokens[$stackPtr]['parenthesis_opener']) === false
3✔
71
            || isset($tokens[$stackPtr]['parenthesis_closer']) === false
3✔
72
            || $tokens[$stackPtr]['parenthesis_opener'] === null
3✔
73
            || $tokens[$stackPtr]['parenthesis_closer'] === null
3✔
74
        ) {
1✔
UNCOV
75
            return;
×
76
        }
77

78
        $this->equalsSpacing           = (int) $this->equalsSpacing;
3✔
79
        $this->requiredSpacesAfterOpen = (int) $this->requiredSpacesAfterOpen;
3✔
80
        $this->requiredSpacesBeforeClose = (int) $this->requiredSpacesBeforeClose;
3✔
81

82
        $this->processBracket($phpcsFile, $tokens[$stackPtr]['parenthesis_opener']);
3✔
83

84
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
3✔
85
            $use = $phpcsFile->findNext(T_USE, ($tokens[$stackPtr]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']);
3✔
86
            if ($use !== false) {
3✔
87
                $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1), null);
3✔
88
                $this->processBracket($phpcsFile, $openBracket);
3✔
89
            }
1✔
90
        }
1✔
91

92
    }//end process()
2✔
93

94

95
    /**
96
     * Processes the contents of a single set of brackets.
97
     *
98
     * @param \PHP_CodeSniffer\Files\File $phpcsFile   The file being scanned.
99
     * @param int                         $openBracket The position of the open bracket
100
     *                                                 in the stack.
101
     *
102
     * @return void
103
     */
104
    public function processBracket($phpcsFile, $openBracket)
3✔
105
    {
106
        $tokens       = $phpcsFile->getTokens();
3✔
107
        $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
3✔
108
        $multiLine    = ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']);
3✔
109

110
        if (isset($tokens[$openBracket]['parenthesis_owner']) === true) {
3✔
111
            $stackPtr = $tokens[$openBracket]['parenthesis_owner'];
3✔
112
        } else {
1✔
113
            $stackPtr = $phpcsFile->findPrevious(T_USE, ($openBracket - 1));
3✔
114
        }
115

116
        $params = $phpcsFile->getMethodParameters($stackPtr);
3✔
117

118
        if (empty($params) === true) {
3✔
119
            // Check spacing around parenthesis.
120
            $next = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), $closeBracket, true);
3✔
121
            if ($next === false) {
3✔
122
                if (($closeBracket - $openBracket) !== 1) {
3✔
123
                    if ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']) {
3✔
UNCOV
124
                        $found = 'newline';
×
125
                    } else {
126
                        $found = $tokens[($openBracket + 1)]['length'];
3✔
127
                    }
128

129
                    $error = 'Expected 0 spaces between parenthesis of function declaration; %s found';
3✔
130
                    $data  = [$found];
3✔
131
                    $fix   = $phpcsFile->addFixableError($error, $openBracket, 'SpacingBetween', $data);
3✔
132
                    if ($fix === true) {
3✔
133
                        $phpcsFile->fixer->replaceToken(($openBracket + 1), '');
3✔
134
                    }
1✔
135
                }
1✔
136

137
                // No params, so we don't check normal spacing rules.
138
                return;
3✔
139
            }
140
        }//end if
1✔
141

142
        foreach ($params as $paramNumber => $param) {
3✔
143
            if ($param['pass_by_reference'] === true) {
3✔
144
                $refToken = $param['reference_token'];
3✔
145

146
                $gap = 0;
3✔
147
                if ($tokens[($refToken + 1)]['code'] === T_WHITESPACE) {
3✔
148
                    $gap = $tokens[($refToken + 1)]['length'];
3✔
149
                }
1✔
150

151
                if ($gap !== 0) {
3✔
152
                    $error = 'Expected 0 spaces after reference operator for argument "%s"; %s found';
3✔
153
                    $data  = [
1✔
154
                        $param['name'],
3✔
155
                        $gap,
3✔
156
                    ];
2✔
157
                    $fix   = $phpcsFile->addFixableError($error, $refToken, 'SpacingAfterReference', $data);
3✔
158
                    if ($fix === true) {
3✔
159
                        $phpcsFile->fixer->replaceToken(($refToken + 1), '');
3✔
160
                    }
1✔
161
                }
1✔
162
            }//end if
1✔
163

164
            if ($param['variable_length'] === true) {
3✔
165
                $variadicToken = $param['variadic_token'];
3✔
166

167
                $gap = 0;
3✔
168
                if ($tokens[($variadicToken + 1)]['code'] === T_WHITESPACE) {
3✔
169
                    $gap = $tokens[($variadicToken + 1)]['length'];
3✔
170
                }
1✔
171

172
                if ($gap !== 0) {
3✔
173
                    $error = 'Expected 0 spaces after variadic operator for argument "%s"; %s found';
3✔
174
                    $data  = [
1✔
175
                        $param['name'],
3✔
176
                        $gap,
3✔
177
                    ];
2✔
178
                    $fix   = $phpcsFile->addFixableError($error, $variadicToken, 'SpacingAfterVariadic', $data);
3✔
179
                    if ($fix === true) {
3✔
180
                        $phpcsFile->fixer->replaceToken(($variadicToken + 1), '');
3✔
181
                    }
1✔
182
                }
1✔
183
            }//end if
1✔
184

185
            if (isset($param['default_equal_token']) === true) {
3✔
186
                $equalToken = $param['default_equal_token'];
3✔
187

188
                $spacesBefore = 0;
3✔
189
                if (($equalToken - $param['token']) > 1) {
3✔
190
                    $spacesBefore = $tokens[($param['token'] + 1)]['length'];
3✔
191
                }
1✔
192

193
                if ($spacesBefore !== $this->equalsSpacing) {
3✔
194
                    $error = 'Incorrect spacing between argument "%s" and equals sign; expected '.$this->equalsSpacing.' but found %s';
3✔
195
                    $data  = [
1✔
196
                        $param['name'],
3✔
197
                        $spacesBefore,
3✔
198
                    ];
2✔
199

200
                    $fix = $phpcsFile->addFixableError($error, $equalToken, 'SpaceBeforeEquals', $data);
3✔
201
                    if ($fix === true) {
3✔
202
                        $padding = str_repeat(' ', $this->equalsSpacing);
3✔
203
                        if ($spacesBefore === 0) {
3✔
UNCOV
204
                            $phpcsFile->fixer->addContentBefore($equalToken, $padding);
×
205
                        } else {
206
                            $phpcsFile->fixer->replaceToken(($equalToken - 1), $padding);
3✔
207
                        }
208
                    }
1✔
209
                }//end if
1✔
210

211
                $spacesAfter = 0;
3✔
212
                if ($tokens[($equalToken + 1)]['code'] === T_WHITESPACE) {
3✔
213
                    $spacesAfter = $tokens[($equalToken + 1)]['length'];
3✔
214
                }
1✔
215

216
                if ($spacesAfter !== $this->equalsSpacing) {
3✔
217
                    $error = 'Incorrect spacing between default value and equals sign for argument "%s"; expected '.$this->equalsSpacing.' but found %s';
3✔
218
                    $data  = [
1✔
219
                        $param['name'],
3✔
220
                        $spacesAfter,
3✔
221
                    ];
2✔
222

223
                    $fix = $phpcsFile->addFixableError($error, $equalToken, 'SpaceAfterEquals', $data);
3✔
224
                    if ($fix === true) {
3✔
225
                        $padding = str_repeat(' ', $this->equalsSpacing);
3✔
226
                        if ($spacesAfter === 0) {
3✔
UNCOV
227
                            $phpcsFile->fixer->addContent($equalToken, $padding);
×
228
                        } else {
229
                            $phpcsFile->fixer->replaceToken(($equalToken + 1), $padding);
3✔
230
                        }
231
                    }
1✔
232
                }//end if
1✔
233
            }//end if
1✔
234

235
            if ($param['type_hint_token'] !== false) {
3✔
236
                $typeHintToken = $param['type_hint_end_token'];
3✔
237

238
                $gap = '';
3✔
239
                $i   = $typeHintToken;
3✔
240
                while ($tokens[++$i]['code'] === T_WHITESPACE) {
3✔
241
                    $gap .= $tokens[$i]['content'];
3✔
242
                }
1✔
243

244
                if ($gap !== ' ') {
3✔
245
                    $error = 'Expected 1 space between type hint and argument "%s"; %s found';
3✔
246
                    $data  = [
1✔
247
                        $param['name'],
3✔
248
                        $gap,
3✔
249
                    ];
2✔
250
                    $fix   = $phpcsFile->addFixableError($error, $typeHintToken, 'SpacingAfterHint', $data);
3✔
251
                    if ($fix === true) {
3✔
252
                        $phpcsFile->fixer->beginChangeset();
3✔
253
                        $i = $typeHintToken;
3✔
254

255
                        if ($tokens[($i + 1)]['code'] === T_WHITESPACE) {
3✔
256
                            $phpcsFile->fixer->replaceToken(++$i, ' ');
3✔
257
                        } else {
1✔
258
                            $phpcsFile->fixer->addContent($typeHintToken, ' ');
3✔
259
                        }
260

261
                        while ($tokens[++$i]['code'] === T_WHITESPACE) {
3✔
NEW
262
                            $phpcsFile->fixer->replaceToken($i, '');
×
263
                        }
264

265
                        $phpcsFile->fixer->endChangeset();
3✔
266
                    }
1✔
267
                }//end if
1✔
268
            }//end if
1✔
269

270
            $commaToken = false;
3✔
271
            if ($paramNumber > 0 && $params[($paramNumber - 1)]['comma_token'] !== false) {
3✔
272
                $commaToken = $params[($paramNumber - 1)]['comma_token'];
3✔
273
            }
1✔
274

275
            if ($commaToken !== false) {
3✔
276
                if ($tokens[($commaToken - 1)]['code'] === T_WHITESPACE) {
3✔
277
                    $error = 'Expected 0 spaces between argument "%s" and comma; %s found';
3✔
278
                    $data  = [
1✔
279
                        $params[($paramNumber - 1)]['name'],
3✔
280
                        $tokens[($commaToken - 1)]['length'],
3✔
281
                    ];
2✔
282

283
                    $fix = $phpcsFile->addFixableError($error, $commaToken, 'SpaceBeforeComma', $data);
3✔
284
                    if ($fix === true) {
3✔
285
                        $phpcsFile->fixer->replaceToken(($commaToken - 1), '');
3✔
286
                    }
1✔
287
                }
1✔
288

289
                // Don't check spacing after the comma if it is the last content on the line.
290
                $checkComma = true;
3✔
291
                if ($multiLine === true) {
3✔
292
                    $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($commaToken + 1), $closeBracket, true);
3✔
293
                    if ($tokens[$next]['line'] !== $tokens[$commaToken]['line']) {
3✔
294
                        $checkComma = false;
3✔
295
                    }
1✔
296
                }
1✔
297

298
                if ($checkComma === true) {
3✔
299
                    if ($param['type_hint_token'] === false) {
3✔
300
                        $spacesAfter = 0;
3✔
301
                        if ($tokens[($commaToken + 1)]['code'] === T_WHITESPACE) {
3✔
302
                            $spacesAfter = $tokens[($commaToken + 1)]['length'];
3✔
303
                        }
1✔
304

305
                        if ($spacesAfter === 0) {
3✔
306
                            $error = 'Expected 1 space between comma and argument "%s"; 0 found';
3✔
307
                            $data  = [$param['name']];
3✔
308
                            $fix   = $phpcsFile->addFixableError($error, $commaToken, 'NoSpaceBeforeArg', $data);
3✔
309
                            if ($fix === true) {
3✔
310
                                $phpcsFile->fixer->addContent($commaToken, ' ');
3✔
311
                            }
1✔
312
                        } else if ($spacesAfter !== 1) {
3✔
313
                            $error = 'Expected 1 space between comma and argument "%s"; %s found';
3✔
314
                            $data  = [
1✔
315
                                $param['name'],
3✔
316
                                $spacesAfter,
3✔
317
                            ];
2✔
318

319
                            $fix = $phpcsFile->addFixableError($error, $commaToken, 'SpacingBeforeArg', $data);
3✔
320
                            if ($fix === true) {
3✔
321
                                $phpcsFile->fixer->replaceToken(($commaToken + 1), ' ');
3✔
322
                            }
1✔
323
                        }//end if
1✔
324
                    } else {
1✔
325
                        $hint = $phpcsFile->getTokensAsString($param['type_hint_token'], (($param['type_hint_end_token'] - $param['type_hint_token']) + 1));
3✔
326
                        if ($param['nullable_type'] === true) {
3✔
327
                            $hint = '?'.$hint;
3✔
328
                        }
1✔
329

330
                        if ($tokens[($commaToken + 1)]['code'] !== T_WHITESPACE) {
3✔
UNCOV
331
                            $error = 'Expected 1 space between comma and type hint "%s"; 0 found';
×
UNCOV
332
                            $data  = [$hint];
×
333
                            $fix   = $phpcsFile->addFixableError($error, $commaToken, 'NoSpaceBeforeHint', $data);
×
334
                            if ($fix === true) {
×
335
                                $phpcsFile->fixer->addContent($commaToken, ' ');
×
336
                            }
337
                        } else {
338
                            $gap = $tokens[($commaToken + 1)]['length'];
3✔
339
                            if ($gap !== 1) {
3✔
340
                                $error = 'Expected 1 space between comma and type hint "%s"; %s found';
3✔
341
                                $data  = [
1✔
342
                                    $hint,
3✔
343
                                    $gap,
3✔
344
                                ];
2✔
345
                                $fix   = $phpcsFile->addFixableError($error, $commaToken, 'SpacingBeforeHint', $data);
3✔
346
                                if ($fix === true) {
3✔
347
                                    $phpcsFile->fixer->replaceToken(($commaToken + 1), ' ');
3✔
348
                                }
1✔
349
                            }
1✔
350
                        }//end if
351
                    }//end if
352
                }//end if
1✔
353
            }//end if
1✔
354
        }//end foreach
1✔
355

356
        // Only check spacing around parenthesis for single line definitions.
357
        if ($multiLine === true) {
3✔
358
            return;
3✔
359
        }
360

361
        $gap = 0;
3✔
362
        if ($tokens[($closeBracket - 1)]['code'] === T_WHITESPACE) {
3✔
363
            $gap = $tokens[($closeBracket - 1)]['length'];
3✔
364
        }
1✔
365

366
        if ($gap !== $this->requiredSpacesBeforeClose) {
3✔
367
            $error = 'Expected %s spaces before closing parenthesis; %s found';
3✔
368
            $data  = [
1✔
369
                $this->requiredSpacesBeforeClose,
3✔
370
                $gap,
3✔
371
            ];
2✔
372
            $fix   = $phpcsFile->addFixableError($error, $closeBracket, 'SpacingBeforeClose', $data);
3✔
373
            if ($fix === true) {
3✔
374
                $padding = str_repeat(' ', $this->requiredSpacesBeforeClose);
3✔
375
                if ($gap === 0) {
3✔
376
                    $phpcsFile->fixer->addContentBefore($closeBracket, $padding);
3✔
377
                } else {
1✔
378
                    $phpcsFile->fixer->replaceToken(($closeBracket - 1), $padding);
3✔
379
                }
380
            }
1✔
381
        }
1✔
382

383
        $gap = 0;
3✔
384
        if ($tokens[($openBracket + 1)]['code'] === T_WHITESPACE) {
3✔
385
            $gap = $tokens[($openBracket + 1)]['length'];
3✔
386
        }
1✔
387

388
        if ($gap !== $this->requiredSpacesAfterOpen) {
3✔
389
            $error = 'Expected %s spaces after opening parenthesis; %s found';
3✔
390
            $data  = [
1✔
391
                $this->requiredSpacesAfterOpen,
3✔
392
                $gap,
3✔
393
            ];
2✔
394
            $fix   = $phpcsFile->addFixableError($error, $openBracket, 'SpacingAfterOpen', $data);
3✔
395
            if ($fix === true) {
3✔
396
                $padding = str_repeat(' ', $this->requiredSpacesAfterOpen);
3✔
397
                if ($gap === 0) {
3✔
398
                    $phpcsFile->fixer->addContent($openBracket, $padding);
3✔
399
                } else {
1✔
400
                    $phpcsFile->fixer->replaceToken(($openBracket + 1), $padding);
3✔
401
                }
402
            }
1✔
403
        }
1✔
404

405
    }//end processBracket()
2✔
406

407

408
}//end class
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc