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

keradus / PHP-CS-Fixer / 16018263876

02 Jul 2025 06:58AM UTC coverage: 94.846% (-0.002%) from 94.848%
16018263876

push

github

keradus
debug2

28193 of 29725 relevant lines covered (94.85%)

45.34 hits per line

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

98.67
/src/Fixer/ClassNotation/SelfStaticAccessorFixer.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\ClassNotation;
16

17
use PhpCsFixer\AbstractFixer;
18
use PhpCsFixer\FixerDefinition\CodeSample;
19
use PhpCsFixer\FixerDefinition\FixerDefinition;
20
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
21
use PhpCsFixer\FixerDefinition\VersionSpecification;
22
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
23
use PhpCsFixer\Tokenizer\FCT;
24
use PhpCsFixer\Tokenizer\Token;
25
use PhpCsFixer\Tokenizer\Tokens;
26
use PhpCsFixer\Tokenizer\TokensAnalyzer;
27

28
final class SelfStaticAccessorFixer extends AbstractFixer
29
{
30
    private const CLASSY_TYPES = [T_CLASS, FCT::T_ENUM];
31
    private const CLASSY_TOKENS_OF_INTEREST = [[T_CLASS], [FCT::T_ENUM]];
32
    private TokensAnalyzer $tokensAnalyzer;
33

34
    public function getDefinition(): FixerDefinitionInterface
35
    {
36
        return new FixerDefinition(
3✔
37
            'Inside an enum or `final`/anonymous class, `self` should be preferred over `static`.',
3✔
38
            [
3✔
39
                new CodeSample(
3✔
40
                    '<?php
3✔
41
final class Sample
42
{
43
    private static $A = 1;
44

45
    public function getBar()
46
    {
47
        return static::class.static::test().static::$A;
48
    }
49

50
    private static function test()
51
    {
52
        return \'test\';
53
    }
54
}
55
'
3✔
56
                ),
3✔
57
                new CodeSample(
3✔
58
                    '<?php
3✔
59
final class Foo
60
{
61
    public function bar()
62
    {
63
        return new static();
64
    }
65
}
66
'
3✔
67
                ),
3✔
68
                new CodeSample(
3✔
69
                    '<?php
3✔
70
final class Foo
71
{
72
    public function isBar()
73
    {
74
        return $foo instanceof static;
75
    }
76
}
77
'
3✔
78
                ),
3✔
79
                new CodeSample(
3✔
80
                    '<?php
3✔
81
$a = new class() {
82
    public function getBar()
83
    {
84
        return static::class;
85
    }
86
};
87
'
3✔
88
                ),
3✔
89
                new VersionSpecificCodeSample(
3✔
90
                    '<?php
3✔
91
enum Foo
92
{
93
    public const A = 123;
94

95
    public static function bar(): void
96
    {
97
        echo static::A;
98
    }
99
}
100
',
3✔
101
                    new VersionSpecification(8_01_00)
3✔
102
                ),
3✔
103
            ]
3✔
104
        );
3✔
105
    }
106

107
    public function isCandidate(Tokens $tokens): bool
108
    {
109
        return $tokens->isTokenKindFound(T_STATIC)
19✔
110
            && $tokens->isAnyTokenKindsFound(self::CLASSY_TYPES)
19✔
111
            && $tokens->isAnyTokenKindsFound([T_DOUBLE_COLON, T_NEW, T_INSTANCEOF]);
19✔
112
    }
113

114
    /**
115
     * {@inheritdoc}
116
     *
117
     * Must run after FinalClassFixer, FinalInternalClassFixer, FunctionToConstantFixer, PhpUnitTestCaseStaticMethodCallsFixer.
118
     */
119
    public function getPriority(): int
120
    {
121
        return -10;
1✔
122
    }
123

124
    protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
125
    {
126
        $this->tokensAnalyzer = new TokensAnalyzer($tokens);
18✔
127
        $classyIndex = $tokens->getNextTokenOfKind(0, self::CLASSY_TOKENS_OF_INTEREST);
18✔
128

129
        while (null !== $classyIndex) {
18✔
130
            if ($tokens[$classyIndex]->isGivenKind(T_CLASS)) {
18✔
131
                $modifiers = $this->tokensAnalyzer->getClassyModifiers($classyIndex);
16✔
132

133
                if (
134
                    isset($modifiers['final'])
16✔
135
                    || $this->tokensAnalyzer->isAnonymousClass($classyIndex)
16✔
136
                ) {
137
                    $classyIndex = $this->fixClassy($tokens, $classyIndex);
14✔
138
                }
139
            } else {
140
                $classyIndex = $this->fixClassy($tokens, $classyIndex);
3✔
141
            }
142

143
            $classyIndex = $tokens->getNextTokenOfKind($classyIndex, self::CLASSY_TOKENS_OF_INTEREST);
18✔
144
        }
145
    }
146

147
    private function fixClassy(Tokens $tokens, int $index): int
148
    {
149
        $index = $tokens->getNextTokenOfKind($index, ['{']);
16✔
150
        $classOpenCount = 1;
16✔
151

152
        while ($classOpenCount > 0) {
16✔
153
            ++$index;
16✔
154

155
            if ($tokens[$index]->equals('{')) {
16✔
156
                ++$classOpenCount;
16✔
157

158
                continue;
16✔
159
            }
160

161
            if ($tokens[$index]->equals('}')) {
16✔
162
                --$classOpenCount;
16✔
163

164
                continue;
16✔
165
            }
166

167
            if ($tokens[$index]->isGivenKind(T_FUNCTION)) {
16✔
168
                // do not fix inside lambda
169
                if ($this->tokensAnalyzer->isLambda($index)) {
12✔
170
                    // figure out where the lambda starts
171
                    $index = $tokens->getNextTokenOfKind($index, ['{']);
2✔
172
                    $openCount = 1;
2✔
173

174
                    do {
175
                        $index = $tokens->getNextTokenOfKind($index, ['}', '{', [T_CLASS]]);
2✔
176
                        if ($tokens[$index]->equals('}')) {
2✔
177
                            --$openCount;
2✔
178
                        } elseif ($tokens[$index]->equals('{')) {
1✔
179
                            ++$openCount;
×
180
                        } else {
181
                            $index = $this->fixClassy($tokens, $index);
1✔
182
                        }
183
                    } while ($openCount > 0);
2✔
184
                }
185

186
                continue;
12✔
187
            }
188

189
            if ($tokens[$index]->isGivenKind([T_NEW, T_INSTANCEOF])) {
16✔
190
                $index = $tokens->getNextMeaningfulToken($index);
9✔
191

192
                if ($tokens[$index]->isGivenKind(T_STATIC)) {
9✔
193
                    $tokens[$index] = new Token([T_STRING, 'self']);
7✔
194
                }
195

196
                continue;
9✔
197
            }
198

199
            if (!$tokens[$index]->isGivenKind(T_STATIC)) {
16✔
200
                continue;
16✔
201
            }
202

203
            $staticIndex = $index;
13✔
204
            $index = $tokens->getNextMeaningfulToken($index);
13✔
205

206
            if (!$tokens[$index]->isGivenKind(T_DOUBLE_COLON)) {
13✔
207
                continue;
7✔
208
            }
209

210
            $tokens[$staticIndex] = new Token([T_STRING, 'self']);
10✔
211
        }
212

213
        return $index;
16✔
214
    }
215
}
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