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

PHPCSStandards / PHP_CodeSniffer / 14454424553

14 Apr 2025 07:49PM UTC coverage: 77.579% (+2.3%) from 75.291%
14454424553

push

github

web-flow
Merge pull request #983 from PHPCSStandards/phpcs-4.0/feature/sq-2448-remove-support-js-css

Remove CSS/JS support (HUGE PR, reviews welcome!)

119 of 126 new or added lines in 14 files covered. (94.44%)

26 existing lines in 10 files now uncovered.

19384 of 24986 relevant lines covered (77.58%)

78.47 hits per line

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

89.36
/src/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php
1
<?php
2
/**
3
 * Ensure single and multi-line function declarations are defined 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\Standards\PEAR\Sniffs\Functions\FunctionDeclarationSniff as PEARFunctionDeclarationSniff;
13
use PHP_CodeSniffer\Util\Tokens;
14

15
class MultiLineFunctionDeclarationSniff extends PEARFunctionDeclarationSniff
16
{
17

18

19
    /**
20
     * Determine if this is a multi-line function declaration.
21
     *
22
     * @param \PHP_CodeSniffer\Files\File $phpcsFile   The file being scanned.
23
     * @param int                         $stackPtr    The position of the current token
24
     *                                                 in the stack passed in $tokens.
25
     * @param int                         $openBracket The position of the opening bracket
26
     *                                                 in the stack passed in $tokens.
27
     * @param array                       $tokens      The stack of tokens that make up
28
     *                                                 the file.
29
     *
30
     * @return bool
31
     */
32
    public function isMultiLineDeclaration($phpcsFile, $stackPtr, $openBracket, $tokens)
3✔
33
    {
34
        $bracketsToCheck = [$stackPtr => $openBracket];
3✔
35

36
        // Closures may use the USE keyword and so be multi-line in this way.
37
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
3✔
38
            $use = $phpcsFile->findNext(T_USE, ($tokens[$openBracket]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']);
3✔
39
            if ($use !== false) {
3✔
40
                $open = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1));
3✔
41
                if ($open !== false) {
3✔
42
                    $bracketsToCheck[$use] = $open;
3✔
43
                }
44
            }
45
        }
46

47
        foreach ($bracketsToCheck as $stackPtr => $openBracket) {
3✔
48
            // If the first argument is on a new line, this is a multi-line
49
            // function declaration, even if there is only one argument.
50
            $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($openBracket + 1), null, true);
3✔
51
            if ($tokens[$next]['line'] !== $tokens[$stackPtr]['line']) {
3✔
52
                return true;
3✔
53
            }
54

55
            $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
3✔
56

57
            $end = $phpcsFile->findEndOfStatement($openBracket + 1);
3✔
58
            while ($tokens[$end]['code'] === T_COMMA) {
3✔
59
                // If the next bit of code is not on the same line, this is a
60
                // multi-line function declaration.
61
                $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($end + 1), $closeBracket, true);
3✔
62
                if ($next === false) {
3✔
63
                    continue(2);
×
64
                }
65

66
                if ($tokens[$next]['line'] !== $tokens[$end]['line']) {
3✔
67
                    return true;
3✔
68
                }
69

70
                $end = $phpcsFile->findEndOfStatement($next);
3✔
71
            }
72

73
            // We've reached the last argument, so see if the next content
74
            // (should be the close bracket) is also on the same line.
75
            $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($end + 1), $closeBracket, true);
3✔
76
            if ($next !== false && $tokens[$next]['line'] !== $tokens[$end]['line']) {
3✔
77
                return true;
×
78
            }
79
        }//end foreach
80

81
        return false;
3✔
82

83
    }//end isMultiLineDeclaration()
84

85

86
    /**
87
     * Processes single-line declarations.
88
     *
89
     * Just uses the Generic BSD-Allman brace sniff.
90
     *
91
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
92
     * @param int                         $stackPtr  The position of the current token
93
     *                                               in the stack passed in $tokens.
94
     * @param array                       $tokens    The stack of tokens that make up
95
     *                                               the file.
96
     *
97
     * @return void
98
     */
99
    public function processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens)
3✔
100
    {
101
        // We do everything the parent sniff does, and a bit more because we
102
        // define multi-line declarations a bit differently.
103
        parent::processSingleLineDeclaration($phpcsFile, $stackPtr, $tokens);
3✔
104

105
        $openingBracket = $tokens[$stackPtr]['parenthesis_opener'];
3✔
106
        $closingBracket = $tokens[$stackPtr]['parenthesis_closer'];
3✔
107

108
        $prevNonWhiteSpace = $phpcsFile->findPrevious(T_WHITESPACE, ($closingBracket - 1), $openingBracket, true);
3✔
109
        if ($tokens[$prevNonWhiteSpace]['line'] !== $tokens[$closingBracket]['line']) {
3✔
110
            $error = 'There must not be a newline before the closing parenthesis of a single-line function declaration';
3✔
111

112
            if (isset(Tokens::$emptyTokens[$tokens[$prevNonWhiteSpace]['code']]) === true) {
3✔
113
                $phpcsFile->addError($error, $closingBracket, 'CloseBracketNewLine');
3✔
114
            } else {
115
                $fix = $phpcsFile->addFixableError($error, $closingBracket, 'CloseBracketNewLine');
3✔
116
                if ($fix === true) {
3✔
117
                    $phpcsFile->fixer->beginChangeset();
3✔
118
                    for ($i = ($closingBracket - 1); $i > $openingBracket; $i--) {
3✔
119
                        if ($tokens[$i]['code'] !== T_WHITESPACE) {
3✔
120
                            break;
3✔
121
                        }
122

123
                        $phpcsFile->fixer->replaceToken($i, '');
3✔
124
                    }
125

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

131
    }//end processSingleLineDeclaration()
1✔
132

133

134
    /**
135
     * Processes multi-line declarations.
136
     *
137
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
138
     * @param int                         $stackPtr  The position of the current token
139
     *                                               in the stack passed in $tokens.
140
     * @param array                       $tokens    The stack of tokens that make up
141
     *                                               the file.
142
     *
143
     * @return void
144
     */
145
    public function processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens)
3✔
146
    {
147
        // We do everything the parent sniff does, and a bit more.
148
        parent::processMultiLineDeclaration($phpcsFile, $stackPtr, $tokens);
3✔
149

150
        $openBracket = $tokens[$stackPtr]['parenthesis_opener'];
3✔
151
        $this->processBracket($phpcsFile, $openBracket, $tokens, 'function');
3✔
152

153
        if ($tokens[$stackPtr]['code'] !== T_CLOSURE) {
3✔
154
            return;
3✔
155
        }
156

157
        $use = $phpcsFile->findNext(T_USE, ($tokens[$stackPtr]['parenthesis_closer'] + 1), $tokens[$stackPtr]['scope_opener']);
3✔
158
        if ($use === false) {
3✔
UNCOV
159
            return;
×
160
        }
161

162
        $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1), null);
3✔
163
        $this->processBracket($phpcsFile, $openBracket, $tokens, 'use');
3✔
164

165
    }//end processMultiLineDeclaration()
1✔
166

167

168
    /**
169
     * Processes the contents of a single set of brackets.
170
     *
171
     * @param \PHP_CodeSniffer\Files\File $phpcsFile   The file being scanned.
172
     * @param int                         $openBracket The position of the open bracket
173
     *                                                 in the stack passed in $tokens.
174
     * @param array                       $tokens      The stack of tokens that make up
175
     *                                                 the file.
176
     * @param string                      $type        The type of the token the brackets
177
     *                                                 belong to (function or use).
178
     *
179
     * @return void
180
     */
181
    public function processBracket($phpcsFile, $openBracket, $tokens, $type='function')
3✔
182
    {
183
        $errorPrefix = '';
3✔
184
        if ($type === 'use') {
3✔
185
            $errorPrefix = 'Use';
3✔
186
        }
187

188
        $closeBracket = $tokens[$openBracket]['parenthesis_closer'];
3✔
189

190
        // The open bracket should be the last thing on the line.
191
        if ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']) {
3✔
192
            $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($openBracket + 1), null, true);
3✔
193
            if ($tokens[$next]['line'] === $tokens[$openBracket]['line']) {
3✔
194
                $error = 'The first parameter of a multi-line '.$type.' declaration must be on the line after the opening bracket';
3✔
195
                $fix   = $phpcsFile->addFixableError($error, $next, $errorPrefix.'FirstParamSpacing');
3✔
196
                if ($fix === true) {
3✔
197
                    if ($tokens[$next]['line'] === $tokens[$openBracket]['line']) {
3✔
198
                        $phpcsFile->fixer->addNewline($openBracket);
3✔
199
                    } else {
200
                        $phpcsFile->fixer->beginChangeset();
×
201
                        for ($x = $openBracket; $x < $next; $x++) {
×
202
                            if ($tokens[$x]['line'] === $tokens[$openBracket]['line']) {
×
203
                                continue;
×
204
                            }
205

206
                            if ($tokens[$x]['line'] === $tokens[$next]['line']) {
×
207
                                break;
×
208
                            }
209
                        }
210

211
                        $phpcsFile->fixer->endChangeset();
×
212
                    }
213
                }
214
            }//end if
215
        }//end if
216

217
        // Each line between the brackets should contain a single parameter.
218
        for ($i = ($openBracket + 1); $i < $closeBracket; $i++) {
3✔
219
            // Skip brackets, like arrays, as they can contain commas.
220
            if (isset($tokens[$i]['bracket_closer']) === true) {
3✔
221
                $i = $tokens[$i]['bracket_closer'];
3✔
222
                continue;
3✔
223
            }
224

225
            if (isset($tokens[$i]['parenthesis_closer']) === true) {
3✔
226
                $i = $tokens[$i]['parenthesis_closer'];
3✔
227
                continue;
3✔
228
            }
229

230
            if (isset($tokens[$i]['attribute_closer']) === true) {
3✔
231
                $i = $tokens[$i]['attribute_closer'];
3✔
232
                continue;
3✔
233
            }
234

235
            if ($tokens[$i]['code'] !== T_COMMA) {
3✔
236
                continue;
3✔
237
            }
238

239
            $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($i + 1), null, true);
3✔
240
            if ($tokens[$next]['line'] === $tokens[$i]['line']) {
3✔
241
                $error = 'Multi-line '.$type.' declarations must define one parameter per line';
3✔
242
                $fix   = $phpcsFile->addFixableError($error, $next, $errorPrefix.'OneParamPerLine');
3✔
243
                if ($fix === true) {
3✔
244
                    $phpcsFile->fixer->addNewline($i);
3✔
245
                }
246
            }
247
        }//end for
248

249
    }//end processBracket()
1✔
250

251

252
}//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

© 2025 Coveralls, Inc