Completed
Push — master ( c6357c...5bad31 )
by Juliette
9s
created

process()   D

Complexity

Conditions 10
Paths 9

Size

Total Lines 42
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 42
rs 4.8196
cc 10
eloc 19
nc 9
nop 2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * PHPCompatibility_Sniffs_PHP_NewKeywordsSniff.
4
 *
5
 * PHP version 5.5
6
 *
7
 * @category  PHP
8
 * @package   PHPCompatibility
9
 * @author    Wim Godden <[email protected]>
10
 * @copyright 2013 Cu.be Solutions bvba
11
 */
12
13
/**
14
 * PHPCompatibility_Sniffs_PHP_NewClassesSniff.
15
 *
16
 * @category  PHP
17
 * @package   PHPCompatibility
18
 * @author    Wim Godden <[email protected]>
19
 * @version   1.0.0
20
 * @copyright 2013 Cu.be Solutions bvba
21
 */
22
class PHPCompatibility_Sniffs_PHP_NewKeywordsSniff extends PHPCompatibility_Sniff
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
23
{
24
25
    /**
26
     * A list of new keywords, not present in older versions.
27
     *
28
     * The array lists : version number with false (not present) or true (present).
29
     * If's sufficient to list the last version which did not contain the keyword.
30
     *
31
     * Description will be used as part of the error message.
32
     * Condition is an array of valid scope conditions to check for.
33
     * If you need a condition of a different type, make sure to add the appropriate
34
     * logic for it as well as this will not resolve itself automatically.
35
     *
36
     * @var array(string => array(string => int|string|null))
37
     */
38
    protected $newKeywords = array(
39
                                        'T_HALT_COMPILER' => array(
40
                                            '5.0' => false,
41
                                            '5.1' => true,
42
                                            'description' => '"__halt_compiler" keyword'
43
                                        ),
44
                                        'T_CONST' => array(
45
                                            '5.2' => false,
46
                                            '5.3' => true,
47
                                            'description' => '"const" keyword',
48
                                            'condition' => array(T_CLASS), // Keyword is only new when not in class context.
49
                                        ),
50
                                        'T_CALLABLE' => array(
51
                                            '5.3' => false,
52
                                            '5.4' => true,
53
                                            'description' => '"callable" keyword',
54
                                            'content' => 'callable',
55
                                        ),
56
                                        'T_DIR' => array(
57
                                            '5.2' => false,
58
                                            '5.3' => true,
59
                                            'description' => '__DIR__ magic constant',
60
                                            'content' => '__DIR__',
61
                                        ),
62
                                        'T_GOTO' => array(
63
                                            '5.2' => false,
64
                                            '5.3' => true,
65
                                            'description' => '"goto" keyword',
66
                                            'content' => 'goto',
67
                                        ),
68
                                        'T_INSTEADOF' => array(
69
                                            '5.3' => false,
70
                                            '5.4' => true,
71
                                            'description' => '"insteadof" keyword (for traits)',
72
                                            'content' => 'insteadof',
73
                                        ),
74
                                        'T_NAMESPACE' => array(
75
                                            '5.2' => false,
76
                                            '5.3' => true,
77
                                            'description' => '"namespace" keyword',
78
                                            'content' => 'namespace',
79
                                        ),
80
                                        'T_NS_C' => array(
81
                                            '5.2' => false,
82
                                            '5.3' => true,
83
                                            'description' => '__NAMESPACE__ magic constant',
84
                                            'content' => '__NAMESPACE__',
85
                                        ),
86
                                        'T_USE' => array(
87
                                            '5.2' => false,
88
                                            '5.3' => true,
89
                                            'description' => '"use" keyword (for traits/namespaces/anonymous functions)'
90
                                        ),
91
                                        'T_TRAIT' => array(
92
                                            '5.3' => false,
93
                                            '5.4' => true,
94
                                            'description' => '"trait" keyword',
95
                                            'content' => 'trait',
96
                                        ),
97
                                        'T_TRAIT_C' => array(
98
                                            '5.3' => false,
99
                                            '5.4' => true,
100
                                            'description' => '__TRAIT__ magic constant',
101
                                            'content' => '__TRAIT__',
102
                                        ),
103
                                        'T_YIELD' => array(
104
                                            '5.4' => false,
105
                                            '5.5' => true,
106
                                            'description' => '"yield" keyword (for generators)',
107
                                            'content' => 'yield',
108
                                        ),
109
                                        'T_FINALLY' => array(
110
                                            '5.4' => false,
111
                                            '5.5' => true,
112
                                            'description' => '"finally" keyword (in exception handling)',
113
                                            'content' => 'finally',
114
                                        ),
115
                                        'T_START_NOWDOC' => array(
116
                                            '5.2' => false,
117
                                            '5.3' => true,
118
                                            'description' => 'nowdoc functionality',
119
                                        ),
120
                                        'T_END_NOWDOC' => array(
121
                                            '5.2' => false,
122
                                            '5.3' => true,
123
                                            'description' => 'nowdoc functionality',
124
                                        ),
125
                                    );
126
127
    /**
128
     * Translation table for T_STRING tokens.
129
     *
130
     * Will be set up from the register() method.
131
     *
132
     * @var array(string => string)
133
     */
134
    protected $translateContentToToken = array();
135
136
137
    /**
138
     * Returns an array of tokens this test wants to listen for.
139
     *
140
     * @return array
141
     */
142
    public function register()
143
    {
144
        $tokens    = array();
145
        $translate = array();
146
        foreach ($this->newKeywords as $token => $versions) {
147
            if (defined($token)) {
148
                $tokens[] = constant($token);
149
            }
150
            if (isset($versions['content'])) {
151
                $translate[$versions['content']] = $token;
152
            }
153
        }
154
155
        /*
156
         * Deal with tokens not recognized by the PHP version the sniffer is run
157
         * under and (not correctly) compensated for by PHPCS.
158
         */
159
        if (empty($translate) === false) {
160
            $this->translateContentToToken = $translate;
161
            $tokens[] = T_STRING;
162
        }
163
164
        return $tokens;
165
166
    }//end register()
167
168
169
    /**
170
     * Processes this test, when one of its tokens is encountered.
171
     *
172
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
173
     * @param int                  $stackPtr  The position of the current token in
174
     *                                        the stack passed in $tokens.
175
     *
176
     * @return void
177
     */
178
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
179
    {
180
        $tokens    = $phpcsFile->getTokens();
181
        $tokenType = $tokens[$stackPtr]['type'];
182
183
        // Translate T_STRING token if necessary.
184
        if ($tokens[$stackPtr]['type'] === 'T_STRING') {
185
            $content = $tokens[$stackPtr]['content'];
186
            if (isset($this->translateContentToToken[$content]) === false) {
187
                // Not one of the tokens we're looking for.
188
                return;
189
            }
190
191
            $tokenType = $this->translateContentToToken[$content];
192
        }
193
194
        $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
195
        $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
196
197
198
        // Skip attempts to use keywords as functions or class names - the former
199
        // will be reported by ForbiddenNamesAsInvokedFunctionsSniff, whilst the
200
        // will be (partially) reported by the ForbiddenNames sniff.
201
        // Either type will result in false-positives when targetting lower versions
202
        // of PHP where the name was not reserved, unless we explicitly check for
203
        // them.
204
        if (
205
            ($nextToken === false || $tokens[$nextToken]['type'] !== 'T_OPEN_PARENTHESIS')
206
            &&
207
            ($prevToken === false || $tokens[$prevToken]['type'] !== 'T_CLASS' || $tokens[$prevToken]['type'] !== 'T_INTERFACE')
208
        ) {
209
            // Skip based on token scope condition.
210
            if (isset($this->newKeywords[$tokenType]['condition'])) {
211
                $condition = $this->newKeywords[$tokenType]['condition'];
212
                if ($this->tokenHasScope($phpcsFile, $stackPtr, $condition) === true) {
213
                    return;
214
                }
215
            }
216
217
            $this->addError($phpcsFile, $stackPtr, $tokenType);
218
        }
219
    }//end process()
220
221
222
    /**
223
     * Generates the error or warning for this sniff.
224
     *
225
     * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
226
     * @param int                  $stackPtr    The position of the function
227
     *                                          in the token array.
228
     * @param string               $keywordName The name of the keyword.
229
     *
230
     * @return void
231
     */
232
    protected function addError($phpcsFile, $stackPtr, $keywordName)
233
    {
234
        $notInVersion = '';
235
        foreach ($this->newKeywords[$keywordName] as $version => $present) {
236
            if (in_array($version, array('condition', 'description', 'content'), true)) {
237
                continue;
238
            }
239
240
            if ($present === false && $this->supportsBelow($version)) {
241
                $notInVersion = $version;
242
            }
243
        }
244
245
        if ($notInVersion !== '') {
246
            $error = '%s is not present in PHP version %s or earlier';
247
            $data  = array(
248
                $this->newKeywords[$keywordName]['description'],
249
                $notInVersion,
250
            );
251
            $phpcsFile->addError($error, $stackPtr, 'Found', $data);
252
        }
253
254
    }//end addError()
255
256
}//end class
257