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

PHPCSStandards / PHP_CodeSniffer / 17663829912

12 Sep 2025 03:38AM UTC coverage: 78.786%. Remained the same
17663829912

Pull #1245

github

web-flow
Merge ccdabfebd into 607b279a1
Pull Request #1245: CS: normalize code style rules [7]

677 of 1022 new or added lines in 17 files covered. (66.24%)

7 existing lines in 1 file now uncovered.

19732 of 25045 relevant lines covered (78.79%)

96.47 hits per line

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

92.77
/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php
1
<?php
2
/**
3
 * Tests self member references.
4
 *
5
 * Verifies that :
6
 * - self:: is used instead of Self::
7
 * - self:: is used for local static member reference
8
 * - self:: is used instead of self ::
9
 *
10
 * @author    Greg Sherwood <gsherwood@squiz.net>
11
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
12
 * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
13
 */
14

15
namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\Classes;
16

17
use PHP_CodeSniffer\Files\File;
18
use PHP_CodeSniffer\Sniffs\AbstractScopeSniff;
19
use PHP_CodeSniffer\Util\Tokens;
20

21
class SelfMemberReferenceSniff extends AbstractScopeSniff
22
{
23

24

25
    /**
26
     * Constructs a Squiz_Sniffs_Classes_SelfMemberReferenceSniff.
27
     */
28
    public function __construct()
3✔
29
    {
30
        parent::__construct([T_CLASS], [T_DOUBLE_COLON]);
3✔
31
    }
1✔
32

33

34
    /**
35
     * Processes the function tokens within the class.
36
     *
37
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
38
     * @param int                         $stackPtr  The position where the token was found.
39
     * @param int                         $currScope The current scope opener token.
40
     *
41
     * @return void
42
     */
43
    protected function processTokenWithinScope(File $phpcsFile, int $stackPtr, int $currScope)
3✔
44
    {
45
        $tokens = $phpcsFile->getTokens();
3✔
46

47
        // Determine if this is a double colon which needs to be examined.
48
        $conditions = $tokens[$stackPtr]['conditions'];
3✔
49
        $conditions = array_reverse($conditions, true);
3✔
50
        foreach ($conditions as $conditionToken => $tokenCode) {
3✔
51
            if ($tokenCode === T_CLASS || $tokenCode === T_ANON_CLASS || $tokenCode === T_CLOSURE) {
3✔
52
                break;
3✔
53
            }
54
        }
55

56
        if ($conditionToken !== $currScope) {
3✔
57
            return;
3✔
58
        }
59

60
        $calledClassName = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($stackPtr - 1), null, true);
3✔
61
        if ($calledClassName === false) {
3✔
62
            // Parse error.
63
            return;
×
64
        }
65

66
        if ($tokens[$calledClassName]['code'] === T_SELF) {
3✔
67
            if ($tokens[$calledClassName]['content'] !== 'self') {
3✔
68
                $error = 'Must use "self::" for local static member reference; found "%s::"';
3✔
69
                $data  = [$tokens[$calledClassName]['content']];
3✔
70
                $fix   = $phpcsFile->addFixableError($error, $calledClassName, 'IncorrectCase', $data);
3✔
71
                if ($fix === true) {
3✔
72
                    $phpcsFile->fixer->replaceToken($calledClassName, 'self');
3✔
73
                }
74

75
                return;
3✔
76
            }
77
        } elseif (isset(Tokens::NAME_TOKENS[$tokens[$calledClassName]['code']]) === true) {
3✔
78
            // Work out the fully qualified name for both the class declaration
79
            // as well as the class usage to see if they match.
80
            $namespaceName = $this->getNamespaceName($phpcsFile, $currScope);
3✔
81
            if ($namespaceName === '\\') {
3✔
82
                $namespaceName = '';
3✔
83
            }
84

85
            $declarationName = $namespaceName . '\\' . $phpcsFile->getDeclarationName($currScope);
3✔
86
            $inlineName      = '';
3✔
87

88
            switch ($tokens[$calledClassName]['code']) {
3✔
89
                case T_NAME_FULLY_QUALIFIED:
3✔
90
                    $inlineName = $tokens[$calledClassName]['content'];
3✔
91
                    break;
3✔
92

93
                case T_NAME_QUALIFIED:
3✔
94
                case T_STRING:
3✔
95
                    $inlineName = $namespaceName . '\\' . $tokens[$calledClassName]['content'];
3✔
96
                    break;
3✔
97

NEW
98
                case T_NAME_RELATIVE:
×
NEW
99
                    $inlineName = $namespaceName . substr($tokens[$calledClassName]['content'], 9);
×
NEW
100
                    break;
×
101
            }
102

103
            if ($declarationName === $inlineName) {
3✔
104
                // Class name is the same as the current class, which is not allowed.
105
                $error = 'Must use "self::" for local static member reference';
3✔
106
                $fix   = $phpcsFile->addFixableError($error, $calledClassName, 'NotUsed');
3✔
107

108
                if ($fix === true) {
3✔
109
                    $phpcsFile->fixer->beginChangeset();
3✔
110
                    $phpcsFile->fixer->replaceToken($calledClassName, '');
3✔
111
                    $phpcsFile->fixer->replaceToken($stackPtr, 'self::');
3✔
112
                    $phpcsFile->fixer->endChangeset();
3✔
113

114
                    // Fix potential whitespace issues in the next loop.
115
                    return;
3✔
116
                }
117
            }
118
        }
119

120
        if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) {
3✔
121
            $found = $tokens[($stackPtr - 1)]['length'];
3✔
122
            $error = 'Expected 0 spaces before double colon; %s found';
3✔
123
            $data  = [$found];
3✔
124
            $fix   = $phpcsFile->addFixableError($error, ($stackPtr - 1), 'SpaceBefore', $data);
3✔
125

126
            if ($fix === true) {
3✔
127
                $phpcsFile->fixer->beginChangeset();
3✔
128

129
                for ($i = ($stackPtr - 1); $tokens[$i]['code'] === T_WHITESPACE; $i--) {
3✔
130
                    $phpcsFile->fixer->replaceToken($i, '');
3✔
131
                }
132

133
                $phpcsFile->fixer->endChangeset();
3✔
134
            }
135
        }
136

137
        if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) {
3✔
138
            $found = $tokens[($stackPtr + 1)]['length'];
3✔
139
            $error = 'Expected 0 spaces after double colon; %s found';
3✔
140
            $data  = [$found];
3✔
141
            $fix   = $phpcsFile->addFixableError($error, ($stackPtr - 1), 'SpaceAfter', $data);
3✔
142

143
            if ($fix === true) {
3✔
144
                $phpcsFile->fixer->beginChangeset();
3✔
145

146
                for ($i = ($stackPtr + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) {
3✔
147
                    $phpcsFile->fixer->replaceToken($i, '');
3✔
148
                }
149

150
                $phpcsFile->fixer->endChangeset();
3✔
151
            }
152
        }
153
    }
1✔
154

155

156
    /**
157
     * Processes a token that is found within the scope that this test is
158
     * listening to.
159
     *
160
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
161
     * @param int                         $stackPtr  The position in the stack where this
162
     *                                               token was found.
163
     *
164
     * @return void
165
     */
166
    protected function processTokenOutsideScope(File $phpcsFile, int $stackPtr)
×
167
    {
168
    }
×
169

170

171
    /**
172
     * Returns the namespace name of the current scope.
173
     *
174
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
175
     * @param int                         $stackPtr  The position where the search for the
176
     *                                               namespace declaration will start.
177
     *
178
     * @return string
179
     */
180
    protected function getNamespaceName(File $phpcsFile, int $stackPtr)
3✔
181
    {
182
        $namespace            = '\\';
3✔
183
        $namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr);
3✔
184

185
        if ($namespaceDeclaration !== false) {
3✔
186
            $tokens       = $phpcsFile->getTokens();
3✔
187
            $nextNonEmpty = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, ($namespaceDeclaration + 1), null, true);
3✔
188
            if ($nextNonEmpty !== false
3✔
189
                && ($tokens[$nextNonEmpty]['code'] === T_NAME_QUALIFIED
3✔
190
                || $tokens[$nextNonEmpty]['code'] === T_STRING)
3✔
191
            ) {
192
                $namespace .= $tokens[$nextNonEmpty]['content'];
3✔
193
            }
194
        }
195

196
        return $namespace;
3✔
197
    }
198
}
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