Completed
Push — master ( 01d73e...c6357c )
by Juliette
03:01
created

PHPCompatibility_Sniffs_PHP_ForbiddenNamesSniff   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 243
Duplicated Lines 6.58 %

Coupling/Cohesion

Components 2
Dependencies 3

Importance

Changes 5
Bugs 1 Features 1
Metric Value
wmc 21
c 5
b 1
f 1
lcom 2
cbo 3
dl 16
loc 243
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A register() 0 8 2
A process() 0 13 2
D processNonString() 8 39 10
C processString() 8 34 7

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
     *
108
     * @var array(string => string)
109
     */
110
    protected $validUseNames = array(
111
        'const'    => true,
112
        'function' => true,
113
    );
114
115
    /**
116
     * targetedTokens
117
     *
118
     * @var array
119
     */
120
    protected $targetedTokens = array(
121
        T_CLASS,
122
        T_FUNCTION,
123
        T_NAMESPACE,
124
        T_STRING,
125
        T_CONST,
126
        T_USE,
127
        T_AS,
128
        T_EXTENDS,
129
        T_TRAIT,
130
        T_INTERFACE,
131
    );
132
133
    /**
134
     * Returns an array of tokens this test wants to listen for.
135
     *
136
     * @return array
137
     */
138
    public function register()
139
    {
140
        $tokens = $this->targetedTokens;
141
        if (defined('T_ANON_CLASS')) {
142
            $tokens[] = constant('T_ANON_CLASS');
143
        }
144
        return $tokens;
145
    }//end register()
146
147
    /**
148
     * Processes this test, when one of its tokens is encountered.
149
     *
150
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
151
     * @param int                  $stackPtr  The position of the current token in the
152
     *                                        stack passed in $tokens.
153
     *
154
     * @return void
155
     */
156
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
157
    {
158
        $tokens = $phpcsFile->getTokens();
159
160
        /**
161
         * We distinguish between the class, function and namespace names or the define statements.
162
         */
163
        if ($tokens[$stackPtr]['type'] === 'T_STRING') {
164
            $this->processString($phpcsFile, $stackPtr, $tokens);
165
        } else {
166
            $this->processNonString($phpcsFile, $stackPtr, $tokens);
167
        }
168
    }
169
170
    /**
171
     * Processes this test, when one of its tokens is encountered.
172
     *
173
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
174
     * @param int                  $stackPtr  The position of the current token in the
175
     *                                        stack passed in $tokens.
176
     * @param array                $tokens    The stack of tokens that make up
177
     *                                        the file.
178
     *
179
     * @return void
180
     */
181
    public function processNonString(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens)
182
    {
183
        $nextNonEmpty = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
184
        if ($nextNonEmpty === false) {
185
            return;
186
        }
187
188
        $nextContentLc = strtolower($tokens[$nextNonEmpty]['content']);
189
        if (isset($this->invalidNames[$nextContentLc]) === false) {
190
            return;
191
        }
192
193
        //  PHP 5.6 allows for use const and use function.
194
        if ($this->supportsAbove('5.6')
195
            && $tokens[$stackPtr]['type'] === 'T_USE'
196
            && isset($this->validUseNames[$nextContentLc]) === true
197
        ) {
198
            return;
199
        }
200
201
        // Deal with anonymous classes.
202
        $prevNonEmpty = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true);
203
        if ($prevNonEmpty !== false
204
            && $tokens[$prevNonEmpty]['type'] === 'T_NEW'
205
            && $tokens[$stackPtr]['type'] === 'T_ANON_CLASS'
206
        ) {
207
            return;
208
        }
209
210 View Code Duplication
        if ($this->supportsAbove($this->invalidNames[$nextContentLc])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
211
            $error = "Function name, class name, namespace name or constant name can not be reserved keyword '%s' (since version %s)";
212
            $data  = array(
213
                $tokens[$nextNonEmpty]['content'],
214
                $this->invalidNames[$nextContentLc],
215
            );
216
            $phpcsFile->addError($error, $stackPtr, 'Found', $data);
217
        }
218
219
    }//end process()
220
221
    /**
222
     * Processes this test, when one of its tokens is encountered.
223
     *
224
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
225
     * @param int                  $stackPtr  The position of the current token in the
226
     *                                        stack passed in $tokens.
227
     * @param array                $tokens    The stack of tokens that make up
228
     *                                        the file.
229
     *
230
     * @return void
231
     */
232
    public function processString(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $tokens)
233
    {
234
        $tokenContentLc = strtolower($tokens[$stackPtr]['content']);
235
236
        // Special case for 5.3 where we want to find usage of traits, but
237
        // trait is not a token.
238
        if ($tokenContentLc === 'trait') {
239
            return $this->processNonString($phpcsFile, $stackPtr, $tokens);
240
        }
241
242
        // Look for any define/defined tokens (both T_STRING ones, blame Tokenizer).
243
        if ($tokenContentLc !== 'define' && $tokenContentLc !== 'defined') {
244
            return;
245
        }
246
247
        // Retrieve the define(d) constant name.
248
        $firstParam = $this->getFunctionCallParameter($phpcsFile, $stackPtr, 1);
249
        if ($firstParam === false) {
250
            return;
251
        }
252
253
        $defineName = strtolower($firstParam['raw']);
254
        $defineName = trim($defineName, '\'"');
255
256 View Code Duplication
        if (isset($this->invalidNames[$defineName]) && $this->supportsAbove($this->invalidNames[$defineName])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
            $error = "Function name, class name, namespace name or constant name can not be reserved keyword '%s' (since PHP version %s)";
258
            $data  = array(
259
                $defineName,
260
                $this->invalidNames[$defineName],
261
            );
262
            $phpcsFile->addError($error, $stackPtr, 'Found', $data);
263
        }
264
265
    }//end process()
266
267
}//end class
268