Completed
Pull Request — master (#126)
by Ryan
04:29 queued 01:40
created

processNonString()   C

Complexity

Conditions 10
Paths 5

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
cc 10
eloc 12
c 4
b 1
f 1
nc 5
nop 3
dl 0
loc 24
rs 5.2164

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_ForbiddenNamesSniff.
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  PHP
8
 * @package   PHPCompatibility
9
 * @author    Wim Godden <[email protected]>
10
 * @copyright 2012 Cu.be Solutions bvba
11
 */
12
13
/**
14
 * PHPCompatibility_Sniffs_PHP_ForbiddenNamesSniff.
15
 *
16
 * Prohibits the use of reserved keywords as class, function, namespace or constant names
17
 *
18
 * PHP version 5.4
19
 *
20
 * @category  PHP
21
 * @package   PHPCompatibility
22
 * @author    Wim Godden <[email protected]>
23
 * @copyright 2012 Cu.be Solutions bvba
24
 */
25
class PHPCompatibility_Sniffs_PHP_ForbiddenNamesSniff extends PHPCompatibility_Sniff
26
{
27
28
    /**
29
     * A list of keywords that can not be used as function, class and namespace name or constant name
30
     * Mentions since which version it's not allowed
31
     *
32
     * @var array(string => string)
33
     */
34
    protected $invalidNames = array(
35
        'abstract' => '5.0',
36
        'and' => 'all',
37
        'array' => 'all',
38
        'as' => 'all',
39
        'break' => 'all',
40
        'callable' => '5.4',
41
        'case' => 'all',
42
        'catch' => '5.0',
43
        'class' => 'all',
44
        'clone' => '5.0',
45
        'const' => 'all',
46
        'continue' => 'all',
47
        'declare' => 'all',
48
        'default' => 'all',
49
        'do' => 'all',
50
        'else' => 'all',
51
        'elseif' => 'all',
52
        'enddeclare' => 'all',
53
        'endfor' => 'all',
54
        'endforeach' => 'all',
55
        'endif' => 'all',
56
        'endswitch' => 'all',
57
        'endwhile' => 'all',
58
        'extends' => 'all',
59
        'final' => '5.0',
60
        'finally' => '5.5',
61
        'for' => 'all',
62
        'foreach' => 'all',
63
        'function' => 'all',
64
        'global' => 'all',
65
        'goto' => '5.3',
66
        'if' => 'all',
67
        'implements' => '5.0',
68
        'interface' => '5.0',
69
        'instanceof' => '5.0',
70
        'insteadof' => '5.4',
71
        'namespace' => '5.3',
72
        'new' => 'all',
73
        'or' => 'all',
74
        'private' => '5.0',
75
        'protected' => '5.0',
76
        'public' => '5.0',
77
        'static' => 'all',
78
        'switch' => 'all',
79
        'throw' => '5.0',
80
        'trait' => '5.4',
81
        'try' => '5.0',
82
        'use' => 'all',
83
        'var' => 'all',
84
        'while' => 'all',
85
        'xor' => 'all',
86
        '__class__' => 'all',
87
        '__dir__' => '5.3',
88
        '__file__' => 'all',
89
        '__function__' => 'all',
90
        '__method__' => 'all',
91
        '__namespace__' => '5.3',
92
        'bool' => '7.0',
93
        'int' => '7.0',
94
        'float' => '7.0',
95
        'string' => '7.0',
96
        'null' => '7.0',
97
        'true' => '7.0',
98
        'false' => '7.0',
99
        'resource' => '7.0',
100
        'object' => '7.0',
101
        'mixed' => '7.0',
102
        'numeric' => '7.0'
103
    );
104
105
    /**
106
     * A list of keywords that can follow use statements.
107
     * Mentions since which version it's not allowed
108
     *
109
     * @var array(string => string)
110
     */
111
    protected $validUseNames = array(
112
        'const',
113
        'function',
114
    );
115
116
    /**
117
     * If true, an error will be thrown; otherwise a warning.
118
     *
119
     * @var bool
120
     */
121
    protected $error = true;
122
123
    /**
124
     * targetedTokens
125
     *
126
     * @var array
127
     */
128
    protected $targetedTokens = array(T_CLASS, T_FUNCTION, T_NAMESPACE, T_STRING, T_CONST, T_USE, T_AS, T_EXTENDS, T_TRAIT);
129
130
    /**
131
     * Returns an array of tokens this test wants to listen for.
132
     *
133
     * @return array
134
     */
135
    public function register()
136
    {
137
        $tokens = $this->targetedTokens;
138
        if (defined('T_ANON_CLASS')) {
139
            $tokens[] = constant('T_ANON_CLASS');
140
        }
141
        return $tokens;
142
    }//end register()
143
144
    /**
145
     * Processes this test, when one of its tokens is encountered.
146
     *
147
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
148
     * @param int                  $stackPtr  The position of the current token in the
149
     *                                        stack passed in $tokens.
150
     *
151
     * @return void
152
     */
153
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
154
    {
155
        $tokens = $phpcsFile->getTokens();
156
157
        /**
158
         * We distinguish between the class, function and namespace names or the define statements
159
         */
160
        if ($tokens[$stackPtr]['type'] == 'T_STRING') {
161
            $this->processString($phpcsFile, $stackPtr, $tokens);
162
        } else {
163
            $this->processNonString($phpcsFile, $stackPtr, $tokens);
164
        }
165
    }
166
167
    /**
168
     * Processes this test, when one of its tokens is encountered.
169
     *
170
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
171
     * @param int                  $stackPtr  The position of the current token in the
172
     *                                        stack passed in $tokens.
173
     * @param array                $tokens    The stack of tokens that make up
174
     *                                        the file.
175
     *
176
     * @return void
177
     */
178
    public function processNonString(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens)
179
    {
180
        if (in_array(strtolower($tokens[$stackPtr + 2]['content']), array_keys($this->invalidNames)) === false) {
181
            return;
182
        }
183
184
        //  PHP 5.6 allows for use const and use function
185
        if ($this->supportsAbove('5.6')
186
            && $tokens[$stackPtr]['type'] == 'T_USE'
187
            && in_array(strtolower($tokens[$stackPtr + 2]['content']), $this->validUseNames)
188
        ) {
189
            return;
190
        }
191
192
        if (isset($tokens[$stackPtr - 2]) && $tokens[$stackPtr - 2]['type'] == 'T_NEW' && $tokens[$stackPtr - 1]['type'] == 'T_WHITESPACE' && $tokens[$stackPtr]['type'] == 'T_ANON_CLASS') {
193
            return;
194
        }
195
196
        if ($this->supportsAbove($this->invalidNames[strtolower($tokens[$stackPtr + 2]['content'])])) {
197
            $error = "Function name, class name, namespace name or constant name can not be reserved keyword '" . $tokens[$stackPtr + 2]['content'] . "' (since version " . $this->invalidNames[strtolower($tokens[$stackPtr + 2]['content'])] . ")";
198
            $phpcsFile->addError($error, $stackPtr);
199
        }
200
201
    }//end process()
202
203
    /**
204
     * Processes this test, when one of its tokens is encountered.
205
     *
206
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
207
     * @param int                  $stackPtr  The position of the current token in the
208
     *                                        stack passed in $tokens.
209
     * @param array                $tokens    The stack of tokens that make up
210
     *                                        the file.
211
     *
212
     * @return void
213
     */
214
    public function processString(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens)
215
    {
216
        // Special case for 5.3 where we want to find usage of traits, but
217
        // trait is not a token.
218
        if ($tokens[$stackPtr]['content'] == 'trait') {
219
            return $this->processNonString($phpcsFile, $stackPtr, $tokens);
220
        }
221
222
        // Look for any define/defined token (both T_STRING ones, blame Tokenizer)
223
        if ($tokens[$stackPtr]['content'] != 'define' && $tokens[$stackPtr]['content'] != 'defined') {
224
            return;
225
        }
226
227
        // Look for the end of the define/defined
228
        $closingParenthesis = $phpcsFile->findNext(T_CLOSE_PARENTHESIS, $stackPtr);
229
        if ($closingParenthesis === false) {
230
            return;
231
        }
232
233
        // Look for define name between current position and end of define/defined
234
        $defineContent = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, $stackPtr, $closingParenthesis);
235
        if ($defineContent === false) {
236
            return;
237
        }
238
239
        foreach ($this->invalidNames as $key => $value) {
240
            if (substr(strtolower($tokens[$defineContent]['content']), 1, -1) == $key) {
241
                $error = "Function name, class name, namespace name or constant name can not be reserved keyword '" . $key . "' (since version " . $value . ")";
242
                $phpcsFile->addError($error, $stackPtr);
243
            }
244
        }
245
    }//end process()
246
247
}//end class
248