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

keradus / PHP-CS-Fixer / 22042339290

15 Feb 2026 08:14PM UTC coverage: 92.957% (-0.2%) from 93.171%
22042339290

push

github

keradus
test: check PHP env in CI jobs

29302 of 31522 relevant lines covered (92.96%)

44.04 hits per line

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

97.83
/src/Fixer/ControlStructure/NoUselessElseFixer.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz RumiƄski <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\Fixer\ControlStructure;
16

17
use PhpCsFixer\AbstractNoUselessElseFixer;
18
use PhpCsFixer\FixerDefinition\CodeSample;
19
use PhpCsFixer\FixerDefinition\FixerDefinition;
20
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
21
use PhpCsFixer\Tokenizer\Tokens;
22
use PhpCsFixer\Tokenizer\TokensAnalyzer;
23

24
/**
25
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
26
 */
27
final class NoUselessElseFixer extends AbstractNoUselessElseFixer
28
{
29
    public function isCandidate(Tokens $tokens): bool
30
    {
31
        return $tokens->isTokenKindFound(\T_ELSE);
284✔
32
    }
33

34
    public function getDefinition(): FixerDefinitionInterface
35
    {
36
        return new FixerDefinition(
3✔
37
            'There should not be useless `else` cases.',
3✔
38
            [
3✔
39
                new CodeSample("<?php\nif (\$a) {\n    return 1;\n} else {\n    return 2;\n}\n"),
3✔
40
            ],
3✔
41
        );
3✔
42
    }
43

44
    /**
45
     * {@inheritdoc}
46
     *
47
     * Must run before BlankLineBeforeStatementFixer, BracesFixer, CombineConsecutiveUnsetsFixer, NoBreakCommentFixer, NoExtraBlankLinesFixer, NoTrailingWhitespaceFixer, NoUselessReturnFixer, NoWhitespaceInBlankLineFixer, SimplifiedIfReturnFixer, StatementIndentationFixer.
48
     * Must run after NoAlternativeSyntaxFixer, NoEmptyStatementFixer, NoUnneededBracesFixer, NoUnneededCurlyBracesFixer.
49
     */
50
    public function getPriority(): int
51
    {
52
        return parent::getPriority();
1✔
53
    }
54

55
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
56
    {
57
        foreach ($tokens as $index => $token) {
284✔
58
            if (!$token->isGivenKind(\T_ELSE)) {
284✔
59
                continue;
284✔
60
            }
61

62
            // `else if` vs. `else` and alternative syntax `else:` checks
63
            if ($tokens[$tokens->getNextMeaningfulToken($index)]->equalsAny([':', [\T_IF]])) {
284✔
64
                continue;
3✔
65
            }
66

67
            // clean up `else` if it is an empty statement
68
            $this->fixEmptyElse($tokens, $index);
284✔
69
            if ($tokens->isEmptyAt($index)) {
284✔
70
                continue;
8✔
71
            }
72

73
            // Clean up `else` if possible.
74
            // Ignore `else` blocks containing named function or classy declarations, because in PHP function/class
75
            // declarations outside any conditional block are always evaluated first, even if the code before the declaration
76
            // returns/throws/etc. So removing such `else` blocks would change the behaviour.
77
            if ($this->isSuperfluousElse($tokens, $index) && !$this->containsNamedSymbolDeclaration($tokens, $index)) {
276✔
78
                $this->clearElse($tokens, $index);
108✔
79
            }
80
        }
81
    }
82

83
    /**
84
     * Remove tokens part of an `else` statement if not empty (i.e. no meaningful tokens inside).
85
     *
86
     * @param int $index T_ELSE index
87
     */
88
    private function fixEmptyElse(Tokens $tokens, int $index): void
89
    {
90
        $next = $tokens->getNextMeaningfulToken($index);
284✔
91

92
        if ($tokens[$next]->equals('{')) {
284✔
93
            $close = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next);
245✔
94
            if (1 === $close - $next) { // '{}'
245✔
95
                $this->clearElse($tokens, $index);
4✔
96
            } elseif ($tokens->getNextMeaningfulToken($next) === $close) { // '{/**/}'
242✔
97
                $this->clearElse($tokens, $index);
3✔
98
            }
99

100
            return;
245✔
101
        }
102

103
        // short `else`
104
        $end = $tokens->getNextTokenOfKind($index, [';', [\T_CLOSE_TAG]]);
40✔
105
        if ($next === $end) {
40✔
106
            $this->clearElse($tokens, $index);
2✔
107
        }
108
    }
109

110
    /**
111
     * @param int $index index of T_ELSE
112
     */
113
    private function clearElse(Tokens $tokens, int $index): void
114
    {
115
        $tokens->clearTokenAndMergeSurroundingWhitespace($index);
116✔
116

117
        // clear T_ELSE and the '{' '}' if there are any
118
        $next = $tokens->getNextMeaningfulToken($index);
116✔
119

120
        if (!$tokens[$next]->equals('{')) {
116✔
121
            return;
2✔
122
        }
123

124
        $tokens->clearTokenAndMergeSurroundingWhitespace($tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next));
114✔
125
        $tokens->clearTokenAndMergeSurroundingWhitespace($next);
114✔
126
    }
127

128
    /**
129
     * @param int $index index of T_ELSE
130
     */
131
    private function containsNamedSymbolDeclaration(Tokens $tokens, int $index): bool
132
    {
133
        $next = $tokens->getNextMeaningfulToken($index);
111✔
134

135
        if (!$tokens[$next]->equals('{')) {
111✔
136
            // short `else` can't contain symbol declaration (`else class Foo {}` is invalid syntax)
137
            return false;
×
138
        }
139

140
        $tokensAnalyzer = new TokensAnalyzer($tokens);
111✔
141
        $close = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $next);
111✔
142
        for ($i = $next + 1; $i < $close; ++$i) {
111✔
143
            if ($tokens[$i]->isGivenKind(\T_FUNCTION) && !$tokensAnalyzer->isLambda($i)) {
111✔
144
                return true;
1✔
145
            }
146

147
            if ($tokens[$i]->isClassy() && !$tokensAnalyzer->isAnonymousClass($i)) {
111✔
148
                return true;
2✔
149
            }
150
        }
151

152
        return false;
108✔
153
    }
154
}
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