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

PHPCSStandards / PHP_CodeSniffer / 17174734458

23 Aug 2025 11:06AM UTC coverage: 76.88% (-2.1%) from 78.934%
17174734458

push

github

jrfnl
TEMP/TESTING PHPUnit 6331

19187 of 24957 relevant lines covered (76.88%)

60.25 hits per line

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

95.45
/src/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php
1
<?php
2
/**
3
 * A Sniff to enforce the use of IDENTICAL type operators rather than EQUAL operators.
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\Squiz\Sniffs\Operators;
11

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

16
class ComparisonOperatorUsageSniff implements Sniff
17
{
18

19
    /**
20
     * A list of valid comparison operators.
21
     *
22
     * @var array
23
     */
24
    private static $validOps = [
25
        T_IS_IDENTICAL        => true,
26
        T_IS_NOT_IDENTICAL    => true,
27
        T_LESS_THAN           => true,
28
        T_GREATER_THAN        => true,
29
        T_IS_GREATER_OR_EQUAL => true,
30
        T_IS_SMALLER_OR_EQUAL => true,
31
        T_INSTANCEOF          => true,
32
    ];
33

34
    /**
35
     * A list of invalid operators with their alternatives.
36
     *
37
     * @var array<int|string, string>
38
     */
39
    private static $invalidOps = [
40
        T_IS_EQUAL     => '===',
41
        T_IS_NOT_EQUAL => '!==',
42
        T_BOOLEAN_NOT  => '=== FALSE',
43
    ];
44

45

46
    /**
47
     * Registers the token types that this sniff wishes to listen to.
48
     *
49
     * @return array<int|string>
50
     */
51
    public function register()
2✔
52
    {
53
        return [
2✔
54
            T_IF,
2✔
55
            T_ELSEIF,
2✔
56
            T_INLINE_THEN,
2✔
57
            T_WHILE,
2✔
58
            T_FOR,
2✔
59
        ];
2✔
60

61
    }//end register()
62

63

64
    /**
65
     * Process the tokens that this sniff is listening for.
66
     *
67
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file where the token was found.
68
     * @param int                         $stackPtr  The position in the stack where the token
69
     *                                               was found.
70
     *
71
     * @return void
72
     */
73
    public function process(File $phpcsFile, $stackPtr)
2✔
74
    {
75
        $tokens = $phpcsFile->getTokens();
2✔
76

77
        if ($tokens[$stackPtr]['code'] === T_INLINE_THEN) {
2✔
78
            $end = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($stackPtr - 1), null, true);
2✔
79
            if ($tokens[$end]['code'] !== T_CLOSE_PARENTHESIS) {
2✔
80
                // This inline IF statement does not have its condition
81
                // bracketed, so we need to guess where it starts.
82
                for ($i = ($end - 1); $i >= 0; $i--) {
2✔
83
                    if ($tokens[$i]['code'] === T_SEMICOLON) {
2✔
84
                        // Stop here as we assume it is the end
85
                        // of the previous statement.
86
                        break;
2✔
87
                    } else if ($tokens[$i]['code'] === T_OPEN_TAG) {
2✔
88
                        // Stop here as this is the start of the file.
89
                        break;
2✔
90
                    } else if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET) {
2✔
91
                        // Stop if this is the closing brace of
92
                        // a code block.
93
                        if (isset($tokens[$i]['scope_opener']) === true) {
2✔
94
                            break;
2✔
95
                        }
96
                    } else if ($tokens[$i]['code'] === T_OPEN_CURLY_BRACKET) {
2✔
97
                        // Stop if this is the opening brace of
98
                        // a code block.
99
                        if (isset($tokens[$i]['scope_closer']) === true) {
2✔
100
                            break;
2✔
101
                        }
102
                    } else if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS) {
2✔
103
                        // Stop if this is the start of a pair of
104
                        // parentheses that surrounds the inline
105
                        // IF statement.
106
                        if (isset($tokens[$i]['parenthesis_closer']) === true
2✔
107
                            && $tokens[$i]['parenthesis_closer'] >= $stackPtr
2✔
108
                        ) {
109
                            break;
2✔
110
                        }
111
                    }//end if
112
                }//end for
113

114
                $start = $phpcsFile->findNext(Tokens::EMPTY_TOKENS, ($i + 1), null, true);
2✔
115
            } else {
116
                if (isset($tokens[$end]['parenthesis_opener']) === false) {
2✔
117
                    return;
×
118
                }
119

120
                $start = $tokens[$end]['parenthesis_opener'];
2✔
121
            }//end if
122
        } else if ($tokens[$stackPtr]['code'] === T_FOR) {
2✔
123
            if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) {
2✔
124
                return;
×
125
            }
126

127
            $openingBracket = $tokens[$stackPtr]['parenthesis_opener'];
2✔
128
            $closingBracket = $tokens[$stackPtr]['parenthesis_closer'];
2✔
129

130
            $start = $phpcsFile->findNext(T_SEMICOLON, $openingBracket, $closingBracket);
2✔
131
            $end   = $phpcsFile->findNext(T_SEMICOLON, ($start + 1), $closingBracket);
2✔
132
            if ($start === false || $end === false) {
2✔
133
                return;
×
134
            }
135
        } else {
136
            if (isset($tokens[$stackPtr]['parenthesis_opener']) === false) {
2✔
137
                return;
×
138
            }
139

140
            $start = $tokens[$stackPtr]['parenthesis_opener'];
2✔
141
            $end   = $tokens[$stackPtr]['parenthesis_closer'];
2✔
142
        }//end if
143

144
        $requiredOps   = 0;
2✔
145
        $foundOps      = 0;
2✔
146
        $foundBooleans = 0;
2✔
147

148
        $lastNonEmpty = $start;
2✔
149

150
        for ($i = $start; $i <= $end; $i++) {
2✔
151
            $type = $tokens[$i]['code'];
2✔
152
            if (isset(self::$invalidOps[$type]) === true) {
2✔
153
                $error = 'Operator %s prohibited; use %s instead';
2✔
154
                $data  = [
2✔
155
                    $tokens[$i]['content'],
2✔
156
                    self::$invalidOps[$type],
2✔
157
                ];
2✔
158
                $phpcsFile->addError($error, $i, 'NotAllowed', $data);
2✔
159
                $foundOps++;
2✔
160
            } else if (isset(self::$validOps[$type]) === true) {
2✔
161
                $foundOps++;
2✔
162
            }
163

164
            if ($type === T_OPEN_PARENTHESIS
2✔
165
                && isset($tokens[$i]['parenthesis_closer']) === true
2✔
166
                && isset(Tokens::FUNCTION_NAME_TOKENS[$tokens[$lastNonEmpty]['code']]) === true
2✔
167
            ) {
168
                $i            = $tokens[$i]['parenthesis_closer'];
2✔
169
                $lastNonEmpty = $i;
2✔
170
                continue;
2✔
171
            }
172

173
            if ($tokens[$i]['code'] === T_TRUE || $tokens[$i]['code'] === T_FALSE) {
2✔
174
                $foundBooleans++;
2✔
175
            }
176

177
            if ($tokens[$i]['code'] === T_NAME_FULLY_QUALIFIED) {
2✔
178
                $compareReadyKeyword = strtolower($tokens[$i]['content']);
2✔
179
                if ($compareReadyKeyword === '\true' || $compareReadyKeyword === '\false') {
2✔
180
                    $foundBooleans++;
2✔
181
                }
182
            }
183

184
            if ($tokens[$i]['code'] === T_BOOLEAN_AND
2✔
185
                || $tokens[$i]['code'] === T_BOOLEAN_OR
2✔
186
            ) {
187
                $requiredOps++;
2✔
188

189
                // When the instanceof operator is used with another operator
190
                // like ===, you can get more ops than are required.
191
                if ($foundOps > $requiredOps) {
2✔
192
                    $foundOps = $requiredOps;
2✔
193
                }
194

195
                // If we get to here and we have not found the right number of
196
                // comparison operators, then we must have had an implicit
197
                // true operation i.e., if ($a) instead of the required
198
                // if ($a === true), so let's add an error.
199
                if ($requiredOps !== $foundOps) {
2✔
200
                    $error = 'Implicit true comparisons prohibited; use === TRUE instead';
2✔
201
                    $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue');
2✔
202
                    $foundOps++;
2✔
203
                }
204
            }
205

206
            if (isset(Tokens::EMPTY_TOKENS[$type]) === false) {
2✔
207
                $lastNonEmpty = $i;
2✔
208
            }
209
        }//end for
210

211
        $requiredOps++;
2✔
212

213
        if ($foundOps < $requiredOps && $requiredOps !== $foundBooleans) {
2✔
214
            $error = 'Implicit true comparisons prohibited; use === TRUE instead';
2✔
215
            $phpcsFile->addError($error, $stackPtr, 'ImplicitTrue');
2✔
216
        }
217

218
    }//end process()
219

220

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

© 2026 Coveralls, Inc