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

PHPCSStandards / PHP_CodeSniffer / 15253296250

26 May 2025 11:55AM UTC coverage: 78.632% (+0.3%) from 78.375%
15253296250

Pull #1105

github

web-flow
Merge d9441d98f into caf806050
Pull Request #1105: Skip tests when 'git' command is not available

19665 of 25009 relevant lines covered (78.63%)

88.67 hits per line

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

97.96
/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php
1
<?php
2
/**
3
 * Checks that the opening brace of a function is on the line after the function declaration.
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\Generic\Sniffs\Functions;
11

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

16
class OpeningFunctionBraceBsdAllmanSniff implements Sniff
17
{
18

19
    /**
20
     * Should this sniff check function braces?
21
     *
22
     * @var boolean
23
     */
24
    public $checkFunctions = true;
25

26
    /**
27
     * Should this sniff check closure braces?
28
     *
29
     * @var boolean
30
     */
31
    public $checkClosures = false;
32

33

34
    /**
35
     * Registers the tokens that this sniff wants to listen for.
36
     *
37
     * @return array<int|string>
38
     */
39
    public function register()
3✔
40
    {
41
        return [
2✔
42
            T_FUNCTION,
3✔
43
            T_CLOSURE,
3✔
44
        ];
2✔
45

46
    }//end register()
47

48

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

62
        if (isset($tokens[$stackPtr]['scope_opener']) === false) {
3✔
63
            return;
3✔
64
        }
65

66
        if (($tokens[$stackPtr]['code'] === T_FUNCTION
3✔
67
            && (bool) $this->checkFunctions === false)
3✔
68
            || ($tokens[$stackPtr]['code'] === T_CLOSURE
3✔
69
            && (bool) $this->checkClosures === false)
3✔
70
        ) {
71
            return;
3✔
72
        }
73

74
        $openingBrace = $tokens[$stackPtr]['scope_opener'];
3✔
75
        $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
3✔
76
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
3✔
77
            $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']);
3✔
78
            if ($use !== false && isset($tokens[$use]['parenthesis_closer']) === true) {
3✔
79
                $closeBracket = $tokens[$use]['parenthesis_closer'];
3✔
80
            }
81
        }
82

83
        // Find the end of the function declaration.
84
        $prev = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($openingBrace - 1), $closeBracket, true);
3✔
85

86
        $functionLine = $tokens[$prev]['line'];
3✔
87
        $braceLine    = $tokens[$openingBrace]['line'];
3✔
88

89
        $lineDifference = ($braceLine - $functionLine);
3✔
90

91
        $metricType = 'Function';
3✔
92
        if ($tokens[$stackPtr]['code'] === T_CLOSURE) {
3✔
93
            $metricType = 'Closure';
3✔
94
        }
95

96
        if ($lineDifference === 0) {
3✔
97
            $error = 'Opening brace should be on a new line';
3✔
98
            $fix   = $phpcsFile->addFixableError($error, $openingBrace, 'BraceOnSameLine');
3✔
99
            if ($fix === true) {
3✔
100
                $hasTrailingAnnotation = false;
3✔
101
                for ($nextLine = ($openingBrace + 1); $nextLine < $phpcsFile->numTokens; $nextLine++) {
3✔
102
                    if ($tokens[$openingBrace]['line'] !== $tokens[$nextLine]['line']) {
3✔
103
                        break;
3✔
104
                    }
105

106
                    if (isset(Tokens::PHPCS_ANNOTATION_TOKENS[$tokens[$nextLine]['code']]) === true) {
3✔
107
                        $hasTrailingAnnotation = true;
3✔
108
                    }
109
                }
110

111
                $phpcsFile->fixer->beginChangeset();
3✔
112
                $indent = $phpcsFile->findFirstOnLine([], $openingBrace);
3✔
113

114
                if ($hasTrailingAnnotation === false || $nextLine === false) {
3✔
115
                    if ($tokens[$indent]['code'] === T_WHITESPACE) {
3✔
116
                        $phpcsFile->fixer->addContentBefore($openingBrace, $tokens[$indent]['content']);
×
117
                    }
118

119
                    if ($tokens[($openingBrace - 1)]['code'] === T_WHITESPACE) {
3✔
120
                        $phpcsFile->fixer->replaceToken(($openingBrace - 1), '');
3✔
121
                    }
122

123
                    $phpcsFile->fixer->addNewlineBefore($openingBrace);
3✔
124
                } else {
125
                    $phpcsFile->fixer->replaceToken($openingBrace, '');
3✔
126
                    $phpcsFile->fixer->addNewlineBefore($nextLine);
3✔
127
                    $phpcsFile->fixer->addContentBefore($nextLine, '{');
3✔
128

129
                    if ($tokens[$indent]['code'] === T_WHITESPACE) {
3✔
130
                        $phpcsFile->fixer->addContentBefore($nextLine, $tokens[$indent]['content']);
×
131
                    }
132
                }
133

134
                $phpcsFile->fixer->endChangeset();
3✔
135
            }//end if
136

137
            $phpcsFile->recordMetric($stackPtr, "$metricType opening brace placement", 'same line');
3✔
138
        } else if ($lineDifference > 1) {
3✔
139
            $error = 'Opening brace should be on the line after the declaration; found %s blank line(s)';
3✔
140
            $data  = [($lineDifference - 1)];
3✔
141

142
            $prevNonWs = $phpcsFile->findPrevious(T_WHITESPACE, ($openingBrace - 1), $closeBracket, true);
3✔
143
            if ($prevNonWs !== $prev) {
3✔
144
                // There must be a comment between the end of the function declaration and the open brace.
145
                // Report, but don't fix.
146
                $phpcsFile->addError($error, $openingBrace, 'BraceSpacing', $data);
3✔
147
            } else {
148
                $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceSpacing', $data);
3✔
149
                if ($fix === true) {
3✔
150
                    $phpcsFile->fixer->beginChangeset();
3✔
151
                    for ($i = $openingBrace; $i > $prev; $i--) {
3✔
152
                        if ($tokens[$i]['line'] === $tokens[$openingBrace]['line']) {
3✔
153
                            if ($tokens[$i]['column'] === 1) {
3✔
154
                                $phpcsFile->fixer->addNewlineBefore($i);
3✔
155
                            }
156

157
                            continue;
3✔
158
                        }
159

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

163
                    $phpcsFile->fixer->endChangeset();
3✔
164
                }
165
            }//end if
166
        }//end if
167

168
        $ignore   = Tokens::PHPCS_ANNOTATION_TOKENS;
3✔
169
        $ignore[] = T_WHITESPACE;
3✔
170
        $next     = $phpcsFile->findNext($ignore, ($openingBrace + 1), null, true);
3✔
171
        if ($tokens[$next]['line'] === $tokens[$openingBrace]['line']) {
3✔
172
            // Only throw this error when this is not an empty function.
173
            if ($next !== $tokens[$stackPtr]['scope_closer']) {
3✔
174
                $error = 'Opening brace must be the last content on the line';
3✔
175
                $fix   = $phpcsFile->addFixableError($error, $openingBrace, 'ContentAfterBrace');
3✔
176
                if ($fix === true) {
3✔
177
                    $phpcsFile->fixer->addNewline($openingBrace);
3✔
178
                }
179
            }
180
        }
181

182
        // Only continue checking if the opening brace looks good.
183
        if ($lineDifference !== 1) {
3✔
184
            return;
3✔
185
        }
186

187
        // We need to actually find the first piece of content on this line,
188
        // as if this is a method with tokens before it (public, static etc)
189
        // or an if with an else before it, then we need to start the scope
190
        // checking from there, rather than the current token.
191
        $lineStart = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true);
3✔
192

193
        // The opening brace is on the correct line, now it needs to be
194
        // checked to be correctly indented.
195
        $startColumn = $tokens[$lineStart]['column'];
3✔
196
        $braceIndent = $tokens[$openingBrace]['column'];
3✔
197

198
        if ($braceIndent !== $startColumn) {
3✔
199
            $expected = ($startColumn - 1);
3✔
200
            $found    = ($braceIndent - 1);
3✔
201

202
            $error = 'Opening brace indented incorrectly; expected %s spaces, found %s';
3✔
203
            $data  = [
2✔
204
                $expected,
3✔
205
                $found,
3✔
206
            ];
2✔
207

208
            $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceIndent', $data);
3✔
209
            if ($fix === true) {
3✔
210
                $indent = str_repeat(' ', $expected);
3✔
211
                if ($found === 0) {
3✔
212
                    $phpcsFile->fixer->addContentBefore($openingBrace, $indent);
3✔
213
                } else {
214
                    $phpcsFile->fixer->replaceToken(($openingBrace - 1), $indent);
3✔
215
                }
216
            }
217
        }//end if
218

219
        $phpcsFile->recordMetric($stackPtr, "$metricType opening brace placement", 'new line');
3✔
220

221
    }//end process()
1✔
222

223

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