• 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

99.03
/src/Standards/Generic/Sniffs/ControlStructures/DisallowYodaConditionsSniff.php
1
<?php
2
/**
3
 * Ban the use of Yoda conditions.
4
 *
5
 * @author    Mponos George <gmponos@gmail.com>
6
 * @author    Mark Scherer <username@example.com>
7
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
8
 * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
9
 */
10

11
namespace PHP_CodeSniffer\Standards\Generic\Sniffs\ControlStructures;
12

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

17
class DisallowYodaConditionsSniff implements Sniff
18
{
19

20

21
    /**
22
     * Returns an array of tokens this test wants to listen for.
23
     *
24
     * @return array<int|string>
25
     */
26
    public function register()
3✔
27
    {
28
        $tokens = Tokens::COMPARISON_TOKENS;
3✔
29
        unset($tokens[T_COALESCE]);
3✔
30

31
        return $tokens;
3✔
32

33
    }//end register()
34

35

36
    /**
37
     * Processes this test, when one of its tokens is encountered.
38
     *
39
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
40
     * @param int                         $stackPtr  The position of the current token in the
41
     *                                               stack passed in $tokens.
42
     *
43
     * @return void
44
     */
45
    public function process(File $phpcsFile, $stackPtr)
3✔
46
    {
47
        $tokens         = $phpcsFile->getTokens();
3✔
48
        $previousIndex  = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($stackPtr - 1), null, true);
3✔
49
        $relevantTokens = [
2✔
50
            T_CLOSE_SHORT_ARRAY,
3✔
51
            T_CLOSE_PARENTHESIS,
3✔
52
            T_TRUE,
3✔
53
            T_FALSE,
3✔
54
            T_NULL,
3✔
55
            T_LNUMBER,
3✔
56
            T_DNUMBER,
3✔
57
            T_CONSTANT_ENCAPSED_STRING,
3✔
58
            T_NAME_FULLY_QUALIFIED,
3✔
59
        ];
2✔
60

61
        if (in_array($tokens[$previousIndex]['code'], $relevantTokens, true) === false) {
3✔
62
            return;
3✔
63
        }
64

65
        // Special case: T_NAME_FULLY_QUALIFIED is only a "relevant" token when it is for a FQN true/false/null.
66
        if ($tokens[$previousIndex]['code'] === T_NAME_FULLY_QUALIFIED) {
3✔
67
            $compareReadyKeyword = strtolower($tokens[$previousIndex]['content']);
3✔
68
            if ($compareReadyKeyword !== '\true'
3✔
69
                && $compareReadyKeyword !== '\false'
3✔
70
                && $compareReadyKeyword !== '\null'
3✔
71
            ) {
72
                return;
×
73
            }
74
        }
75

76
        if ($tokens[$previousIndex]['code'] === T_CLOSE_SHORT_ARRAY) {
3✔
77
            $previousIndex = $tokens[$previousIndex]['bracket_opener'];
3✔
78
            if ($this->isArrayStatic($phpcsFile, $previousIndex) === false) {
3✔
79
                return;
3✔
80
            }
81
        }
82

83
        $prevIndex = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($previousIndex - 1), null, true);
3✔
84

85
        if (in_array($tokens[$prevIndex]['code'], Tokens::ARITHMETIC_TOKENS, true) === true) {
3✔
86
            return;
3✔
87
        }
88

89
        if ($tokens[$prevIndex]['code'] === T_STRING_CONCAT) {
3✔
90
            return;
3✔
91
        }
92

93
        // Is it a parenthesis.
94
        if ($tokens[$previousIndex]['code'] === T_CLOSE_PARENTHESIS) {
3✔
95
            $beforeOpeningParenthesisIndex = $phpcsFile->findPrevious(
3✔
96
                Tokens::EMPTY_TOKENS,
3✔
97
                ($tokens[$previousIndex]['parenthesis_opener'] - 1),
3✔
98
                null,
3✔
99
                true
3✔
100
            );
2✔
101

102
            if ($beforeOpeningParenthesisIndex === false || $tokens[$beforeOpeningParenthesisIndex]['code'] !== T_ARRAY) {
3✔
103
                if (isset(Tokens::NAME_TOKENS[$tokens[$beforeOpeningParenthesisIndex]['code']]) === true) {
3✔
104
                    return;
3✔
105
                }
106

107
                // If it is not an array check what is inside.
108
                $found = $phpcsFile->findPrevious(
3✔
109
                    T_VARIABLE,
3✔
110
                    ($previousIndex - 1),
3✔
111
                    $tokens[$previousIndex]['parenthesis_opener']
3✔
112
                );
2✔
113

114
                // If a variable exists, it is not Yoda.
115
                if ($found !== false) {
3✔
116
                    return;
3✔
117
                }
118

119
                // If there is nothing inside the parenthesis, it is not a Yoda condition.
120
                $opener = $tokens[$previousIndex]['parenthesis_opener'];
3✔
121
                $prev   = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($previousIndex - 1), ($opener + 1), true);
3✔
122
                if ($prev === false) {
3✔
123
                    return;
3✔
124
                }
125
            } else if ($tokens[$beforeOpeningParenthesisIndex]['code'] === T_ARRAY
3✔
126
                && $this->isArrayStatic($phpcsFile, $beforeOpeningParenthesisIndex) === false
3✔
127
            ) {
128
                return;
3✔
129
            }//end if
130
        }//end if
131

132
        $phpcsFile->addError(
3✔
133
            'Usage of Yoda conditions is not allowed; switch the expression order',
3✔
134
            $stackPtr,
3✔
135
            'Found'
3✔
136
        );
2✔
137

138
    }//end process()
1✔
139

140

141
    /**
142
     * Determines if an array is a static definition.
143
     *
144
     * @param \PHP_CodeSniffer\Files\File $phpcsFile  The file being scanned.
145
     * @param int                         $arrayToken The position of the array token.
146
     *
147
     * @return bool
148
     */
149
    public function isArrayStatic(File $phpcsFile, $arrayToken)
3✔
150
    {
151
        $tokens = $phpcsFile->getTokens();
3✔
152

153
        if ($tokens[$arrayToken]['code'] === T_OPEN_SHORT_ARRAY) {
3✔
154
            $start = $arrayToken;
3✔
155
            $end   = $tokens[$arrayToken]['bracket_closer'];
3✔
156
        } else if ($tokens[$arrayToken]['code'] === T_ARRAY) {
3✔
157
            $start = $tokens[$arrayToken]['parenthesis_opener'];
3✔
158
            $end   = $tokens[$arrayToken]['parenthesis_closer'];
3✔
159
        } else {
160
            // Shouldn't be possible but may happen if external sniffs are using this method.
161
            return true; // @codeCoverageIgnore
162
        }
163

164
        $staticTokens  = Tokens::EMPTY_TOKENS;
3✔
165
        $staticTokens += Tokens::TEXT_STRING_TOKENS;
3✔
166
        $staticTokens += Tokens::ASSIGNMENT_TOKENS;
3✔
167
        $staticTokens += Tokens::EQUALITY_TOKENS;
3✔
168
        $staticTokens += Tokens::COMPARISON_TOKENS;
3✔
169
        $staticTokens += Tokens::ARITHMETIC_TOKENS;
3✔
170
        $staticTokens += Tokens::OPERATORS;
3✔
171
        $staticTokens += Tokens::BOOLEAN_OPERATORS;
3✔
172
        $staticTokens += Tokens::CAST_TOKENS;
3✔
173
        $staticTokens += Tokens::BRACKET_TOKENS;
3✔
174
        $staticTokens += [
2✔
175
            T_DOUBLE_ARROW => T_DOUBLE_ARROW,
3✔
176
            T_COMMA        => T_COMMA,
3✔
177
            T_TRUE         => T_TRUE,
3✔
178
            T_FALSE        => T_FALSE,
3✔
179
            T_NULL         => T_NULL,
3✔
180
        ];
2✔
181

182
        for ($i = ($start + 1); $i < $end; $i++) {
3✔
183
            if (isset($tokens[$i]['scope_closer']) === true) {
3✔
184
                $i = $tokens[$i]['scope_closer'];
3✔
185
                continue;
3✔
186
            }
187

188
            // Special case: T_NAME_FULLY_QUALIFIED is only a "static" token when it is for a FQN true/false/null.
189
            if ($tokens[$i]['code'] === T_NAME_FULLY_QUALIFIED) {
3✔
190
                $compareReadyKeyword = strtolower($tokens[$i]['content']);
3✔
191
                if ($compareReadyKeyword === '\true'
3✔
192
                    || $compareReadyKeyword === '\false'
3✔
193
                    || $compareReadyKeyword === '\null'
3✔
194
                ) {
195
                    continue;
3✔
196
                }
197
            }
198

199
            if (isset($staticTokens[$tokens[$i]['code']]) === false) {
3✔
200
                return false;
3✔
201
            }
202
        }//end for
203

204
        return true;
3✔
205

206
    }//end isArrayStatic()
207

208

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