Completed
Push — master ( 50932b...737862 )
by Wim
9s
created

process()   C

Complexity

Conditions 8
Paths 4

Size

Total Lines 36
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 2
Metric Value
c 4
b 2
f 2
dl 0
loc 36
rs 5.3846
cc 8
eloc 18
nc 4
nop 2
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 first version where the keyword appears.
30
     *
31
     * If you add a condition, make sure to add the appropriate logic for it as well as
32
     * this will not resolve itself automatically.
33
     *
34
     * @var array(string => array(string => int|string|null))
35
     */
36
    protected $newKeywords = array(
37
                                        'T_HALT_COMPILER' => array(
38
                                            '5.0' => false,
39
                                            '5.1' => true,
40
                                            'description' => '"__halt_compiler" keyword'
41
                                        ),
42
                                        'T_CONST' => array(
43
                                            '5.2' => false,
44
                                            '5.3' => true,
45
                                            'description' => '"const" keyword',
46
                                            'condition' => 'T_CLASS', // Keyword is only new when not in class context.
47
                                        ),
48
                                        'T_CALLABLE' => array(
49
                                            '5.3' => false,
50
                                            '5.4' => true,
51
                                            'description' => '"callable" keyword'
52
                                        ),
53
                                        'T_DIR' => array(
54
                                            '5.2' => false,
55
                                            '5.3' => true,
56
                                            'description' => '__DIR__ magic constant'
57
                                        ),
58
                                        'T_GOTO' => array(
59
                                            '5.2' => false,
60
                                            '5.3' => true,
61
                                            'description' => '"goto" keyword'
62
                                        ),
63
                                        'T_INSTEADOF' => array(
64
                                            '5.3' => false,
65
                                            '5.4' => true,
66
                                            'description' => '"insteadof" keyword (for traits)'
67
                                        ),
68
                                        'T_NAMESPACE' => array(
69
                                            '5.2' => false,
70
                                            '5.3' => true,
71
                                            'description' => '"namespace" keyword'
72
                                        ),
73
                                        'T_NS_C' => array(
74
                                            '5.2' => false,
75
                                            '5.3' => true,
76
                                            'description' => '__NAMESPACE__ magic constant'
77
                                        ),
78
                                        'T_USE' => array(
79
                                            '5.2' => false,
80
                                            '5.3' => true,
81
                                            'description' => '"use" keyword (for traits/namespaces/anonymous functions)'
82
                                        ),
83
                                        'T_TRAIT' => array(
84
                                            '5.3' => false,
85
                                            '5.4' => true,
86
                                            'description' => '"trait" keyword'
87
                                        ),
88
                                        'T_TRAIT_C' => array(
89
                                            '5.3' => false,
90
                                            '5.4' => true,
91
                                            'description' => '__TRAIT__ magic constant'
92
                                        ),
93
                                        'T_YIELD' => array(
94
                                            '5.4' => false,
95
                                            '5.5' => true,
96
                                            'description' => '"yield" keyword (for generators)'
97
                                        ),
98
                                        'T_FINALLY' => array(
99
                                            '5.4' => false,
100
                                            '5.5' => true,
101
                                            'description' => '"finally" keyword (in exception handling)'
102
                                        ),
103
                                        'T_START_NOWDOC' => array(
104
                                            '5.2' => false,
105
                                            '5.3' => true,
106
                                            'description' => 'nowdoc functionality'
107
                                        ),
108
                                        'T_END_NOWDOC' => array(
109
                                            '5.2' => false,
110
                                            '5.3' => true,
111
                                            'description' => 'nowdoc functionality'
112
                                        ),
113
                                    );
114
115
116
    /**
117
     * Returns an array of tokens this test wants to listen for.
118
     *
119
     * @return array
120
     */
121
    public function register()
122
    {
123
        $tokens = array();
124
        foreach ($this->newKeywords as $token => $versions) {
125
            if (defined($token)) {
126
                $tokens[] = constant($token);
127
            }
128
        }
129
        return $tokens;
130
131
    }//end register()
132
133
134
    /**
135
     * Processes this test, when one of its tokens is encountered.
136
     *
137
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
138
     * @param int                  $stackPtr  The position of the current token in
139
     *                                        the stack passed in $tokens.
140
     *
141
     * @return void
142
     */
143
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
144
    {
145
        $tokens = $phpcsFile->getTokens();
146
147
        $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
148
        $prevToken = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
149
150
        // Skip attempts to use keywords as functions or class names - the former
151
        // will be reported by FrobiddenNamesAsInvokedFunctionsSniff, whilst the
152
        // latter doesn't yet have an appropriate sniff.
153
        // Either type will result in false-positives when targetting lower versions
154
        // of PHP where the name was not reserved, unless we explicitly check for
155
        // them.
156
        if (
157
            $tokens[$nextToken]['type'] != 'T_OPEN_PARENTHESIS'
158
            &&
159
            $tokens[$prevToken]['type'] != 'T_CLASS'
160
        ) {
161
            // Skip based on special conditions.
162
            if (
163
                isset($this->newKeywords[$tokens[$stackPtr]['type']]['condition'])
164
                &&
165
                (empty($tokens[$stackPtr]['conditions']) === false
166
                &&
167
                is_array($tokens[$stackPtr]['conditions']))
168
            ) {
169
                foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condType) {
170
                    if ($condType === constant($this->newKeywords[$tokens[$stackPtr]['type']]['condition'])) {
171
                        return;
172
                    }
173
                }
174
            }
175
176
            $this->addError($phpcsFile, $stackPtr, $tokens[$stackPtr]['type']);
177
        }
178
    }//end process()
179
180
181
    /**
182
     * Generates the error or warning for this sniff.
183
     *
184
     * @param PHP_CodeSniffer_File $phpcsFile   The file being scanned.
185
     * @param int                  $stackPtr    The position of the function
186
     *                                          in the token array.
187
     * @param string               $keywordName The name of the keyword.
188
     * @param string               $pattern     The pattern used for the match.
189
     *
190
     * @return void
191
     */
192
    protected function addError($phpcsFile, $stackPtr, $keywordName, $pattern=null)
193
    {
194
        if ($pattern === null) {
195
            $pattern = $keywordName;
196
        }
197
198
        $error = '';
199
200
        $isError = false;
201
        foreach ($this->newKeywords[$pattern] as $version => $present) {
202
            if (in_array($version, array('condition', 'description'), true)) {
203
                continue;
204
            }
205
206
            if ($this->supportsBelow($version)) {
207
                if ($present === false) {
208
                    $isError = true;
209
                    $error .= 'not present in PHP version ' . $version . ' or earlier';
210
                }
211
            }
212
        }
213
        if (strlen($error) > 0) {
214
            $error = $this->newKeywords[$keywordName]['description'] . ' is ' . $error;
215
216
            if ($isError === true) {
217
                $phpcsFile->addError($error, $stackPtr);
218
            } else {
219
                $phpcsFile->addWarning($error, $stackPtr);
220
            }
221
        }
222
    }//end addError()
223
224
}//end class
225