• 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

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

32
    }//end __construct()
1✔
33

34

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

155
    }//end processTokenWithinScope()
1✔
156

157

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

171
    }//end processTokenOutsideScope()
×
172

173

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

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

199
        return $namespace;
3✔
200

201
    }//end getNamespaceName()
202

203

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