Completed
Push — master ( a8f526...c8097e )
by Wim
02:57
created

process()   D

Complexity

Conditions 20
Paths 48

Size

Total Lines 82
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 2 Features 1
Metric Value
cc 20
eloc 46
c 4
b 2
f 1
nc 48
nop 2
dl 0
loc 82
rs 4.9176

How to fix   Long Method    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_RemovedExtensionsSniff.
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_RemovedExtensionsSniff.
15
 *
16
 * Discourages the use of removed extensions. Suggests alternative extensions if available
17
 *
18
 * @category  PHP
19
 * @package   PHPCompatibility
20
 * @author    Wim Godden <[email protected]>
21
 * @copyright 2012 Cu.be Solutions bvba
22
 */
23
class PHPCompatibility_Sniffs_PHP_RemovedExtensionsSniff extends PHPCompatibility_Sniff
24
{
25
    /**
26
     * A list of functions to whitelist, if any.
27
     *
28
     * This is intended for projects using functions which start with the same
29
     * prefix as one of the removed extensions.
30
     *
31
     * This property can be set from the ruleset, like so:
32
     * <rule ref="PHPCompatibility.PHP.RemovedExtensions">
33
     *   <properties>
34
     *     <property name="functionWhitelist" type="array" value="mysql_to_rfc3339,mysql_another_function" />
35
     *   </properties>
36
     * </rule>
37
     *
38
     * @var array
39
     */
40
    public $functionWhitelist;
41
42
    /**
43
     * A list of removed extensions with their alternative, if any
44
     * Array codes : 0 = removed/unavailable, -1 = deprecated, 1 = active
45
     *
46
     * @var array(string|null)
47
     */
48
    protected $removedExtensions = array(
49
        'activescript' => array(
50
                '5.0' => 1,
51
                '5.1' => 1,
52
                '5.2' => 1,
53
                '5.3' => 0,
54
                '5.4' => 0,
55
                '5.5' => 0,
56
                '5.6' => 0,
57
                '7.0' => 0,
58
                'alternative' => 'pecl/activescript'
59
        ),
60
        'cpdf' => array(
61
                '5.0' => 1,
62
                '5.1' => 1,
63
                '5.2' => 1,
64
                '5.3' => 0,
65
                '5.4' => 0,
66
                '5.5' => 0,
67
                '5.6' => 0,
68
                '7.0' => 0,
69
                'alternative' => 'pecl/pdflib'
70
        ),
71
        'dbase' => array(
72
                '5.0' => 1,
73
                '5.1' => 1,
74
                '5.2' => 1,
75
                '5.3' => 0,
76
                '5.4' => 0,
77
                '5.5' => 0,
78
                '5.6' => 0,
79
                '7.0' => 0,
80
                'alternative' => null
81
        ),
82
        'dbx' => array(
83
                '5.0' => 1,
84
                '5.1' => 0,
85
                '5.2' => 0,
86
                '5.3' => 0,
87
                '5.4' => 0,
88
                '5.5' => 0,
89
                '5.6' => 0,
90
                '7.0' => 0,
91
                'alternative' => 'pecl/dbx'
92
        ),
93
        'dio' => array(
94
                '5.0' => 1,
95
                '5.1' => 0,
96
                '5.2' => 0,
97
                '5.3' => 0,
98
                '5.4' => 0,
99
                '5.5' => 0,
100
                '5.6' => 0,
101
                '7.0' => 0,
102
                'alternative' => 'pecl/dio'
103
        ),
104
        'ereg' => array(
105
                '5.0' => 1,
106
                '5.1' => 1,
107
                '5.2' => 1,
108
                '7.0' => 0,
109
                'alternative' => null
110
        ),
111
        'fam' => array(
112
                '5.0' => 1,
113
                '5.1' => 0,
114
                '5.2' => 0,
115
                '5.3' => 0,
116
                '5.4' => 0,
117
                '5.5' => 0,
118
                '5.6' => 0,
119
                '7.0' => 0,
120
                'alternative' => null
121
        ),
122
        'fbsql' => array(
123
                '5.0' => 1,
124
                '5.1' => 1,
125
                '5.2' => 1,
126
                '5.3' => 0,
127
                '5.4' => 0,
128
                '5.5' => 0,
129
                '5.6' => 0,
130
                '7.0' => 0,
131
                'alternative' => null
132
        ),
133
        'fdf' => array(
134
                '5.0' => 1,
135
                '5.1' => 1,
136
                '5.2' => 1,
137
                '5.3' => 0,
138
                '5.4' => 0,
139
                '5.5' => 0,
140
                '5.6' => 0,
141
                '7.0' => 0,
142
                'alternative' => 'pecl/fdf'
143
        ),
144
        'filepro' => array(
145
                '5.0' => 1,
146
                '5.1' => 1,
147
                '5.2' => 0,
148
                '5.3' => 0,
149
                '5.4' => 0,
150
                '5.5' => 0,
151
                '5.6' => 0,
152
                '7.0' => 0,
153
                'alternative' => null
154
        ),
155
        'hw_api' => array(
156
                '5.0' => 1,
157
                '5.1' => 1,
158
                '5.2' => 0,
159
                '5.3' => 0,
160
                '5.4' => 0,
161
                '5.5' => 0,
162
                '5.6' => 0,
163
                '7.0' => 0,
164
                'alternative' => null
165
        ),
166
        'ingres' => array(
167
                '5.0' => 1,
168
                '5.1' => 0,
169
                '5.2' => 0,
170
                '5.3' => 0,
171
                '5.4' => 0,
172
                '5.5' => 0,
173
                '5.6' => 0,
174
                '7.0' => 0,
175
                'alternative' => 'pecl/ingres'
176
        ),
177
        'ircg' => array(
178
                '5.0' => 1,
179
                '5.1' => 1,
180
                '5.2' => 1,
181
                '5.3' => 0,
182
                '5.4' => 0,
183
                '5.5' => 0,
184
                '5.6' => 0,
185
                '7.0' => 0,
186
                'alternative' => null
187
        ),
188
        'mcve' => array(
189
                '5.0' => 1,
190
                '5.1' => 0,
191
                '5.2' => 0,
192
                '5.3' => 0,
193
                '5.4' => 0,
194
                '5.5' => 0,
195
                '5.6' => 0,
196
                '7.0' => 0,
197
                'alternative' => 'pecl/mvce'
198
        ),
199
        'ming' => array(
200
                '5.0' => 1,
201
                '5.1' => 1,
202
                '5.2' => 1,
203
                '5.3' => 0,
204
                '5.4' => 0,
205
                '5.5' => 0,
206
                '5.6' => 0,
207
                '7.0' => 0,
208
                'alternative' => 'pecl/ming'
209
        ),
210
        'mnogosearch' => array(
211
                '5.0' => 1,
212
                '5.1' => 0,
213
                '5.2' => 0,
214
                '5.3' => 0,
215
                '5.4' => 0,
216
                '5.5' => 0,
217
                '5.6' => 0,
218
                '7.0' => 0,
219
                'alternative' => null
220
        ),
221
        'msql' => array(
222
                '5.0' => 1,
223
                '5.1' => 1,
224
                '5.2' => 1,
225
                '5.3' => 0,
226
                '5.4' => 0,
227
                '5.5' => 0,
228
                '5.6' => 0,
229
                '7.0' => 0,
230
                'alternative' => null
231
        ),
232
        'mssql' => array(
233
                '7.0' => 0,
234
                'alternative' => null
235
        ),
236
        'mysql_' => array(
237
                '5.0' => 1,
238
                '5.1' => 1,
239
                '5.2' => 1,
240
                '5.3' => 1,
241
                '5.4' => 1,
242
                '5.5' => -1,
243
                '5.6' => -1,
244
                '7.0' => 0,
245
                'alternative' => 'mysqli',
246
        ),
247
        'ncurses' => array(
248
                '5.0' => 1,
249
                '5.1' => 1,
250
                '5.2' => 1,
251
                '5.3' => 0,
252
                '5.4' => 0,
253
                '5.5' => 0,
254
                '5.6' => 0,
255
                '7.0' => 0,
256
                'alternative' => 'pecl/ncurses'
257
        ),
258
        'oracle' => array(
259
                '5.0' => 1,
260
                '5.1' => 1,
261
                '5.2' => 1,
262
                '5.3' => 0,
263
                '5.4' => 0,
264
                '5.5' => 0,
265
                '5.6' => 0,
266
                '7.0' => 0,
267
                'alternative' => 'oci8 or pdo_oci'
268
        ),
269
        'ovrimos' => array(
270
                '5.0' => 1,
271
                '5.1' => 0,
272
                '5.2' => 0,
273
                '5.3' => 0,
274
                '5.4' => 0,
275
                '5.5' => 0,
276
                '5.6' => 0,
277
                '7.0' => 0,
278
                'alternative' => null
279
        ),
280
        'pfpro' => array(
281
                '5.0' => 1,
282
                '5.1' => 1,
283
                '5.2' => 1,
284
                '5.3' => 0,
285
                '5.4' => 0,
286
                '5.5' => 0,
287
                '5.6' => 0,
288
                '7.0' => 0,
289
                'alternative' => null
290
        ),
291
        'sqlite' => array(
292
                '5.0' => 1,
293
                '5.1' => 1,
294
                '5.2' => 1,
295
                '5.3' => 1,
296
                '5.4' => 0,
297
                '5.5' => 0,
298
                '5.6' => 0,
299
                '7.0' => 0,
300
                'alternative' => null
301
        ),
302
        'sybase' => array(
303
                '5.0' => 1,
304
                '5.1' => 1,
305
                '5.2' => 1,
306
                '5.3' => 0,
307
                '5.4' => 0,
308
                '5.5' => 0,
309
                '5.6' => 0,
310
                '7.0' => 0,
311
                'alternative' => 'sybase_ct'
312
        ),
313
        'sybase_ct' => array(
314
                '7.0' => 0,
315
                'alternative' => null
316
        ),
317
        'w32api' => array(
318
                '5.0' => 1,
319
                '5.1' => 0,
320
                '5.2' => 0,
321
                '5.3' => 0,
322
                '5.4' => 0,
323
                '5.5' => 0,
324
                '5.6' => 0,
325
                '7.0' => 0,
326
                'alternative' => 'pecl/ffi'
327
        ),
328
        'yp' => array(
329
                '5.0' => 1,
330
                '5.1' => 1,
331
                '5.2' => 1,
332
                '5.3' => 0,
333
                '5.4' => 0,
334
                '5.5' => 0,
335
                '5.6' => 0,
336
                '7.0' => 0,
337
                'alternative' => null
338
        ),
339
    );
340
341
    /**
342
     * Returns an array of tokens this test wants to listen for.
343
     *
344
     * @return array
345
     */
346
    public function register()
347
    {
348
        return array(T_STRING);
349
350
    }//end register()
351
352
    /**
353
     * Processes this test, when one of its tokens is encountered.
354
     *
355
     * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
356
     * @param int                  $stackPtr  The position of the current token in the
357
     *                                        stack passed in $tokens.
358
     *
359
     * @return void
360
     */
361
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
362
    {
363
        $tokens = $phpcsFile->getTokens();
364
365
        // Find the next non-empty token.
366
        $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
367
368
        if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) {
369
            // Not a function call.
370
            return;
371
        }
372
373
        if (isset($tokens[$openBracket]['parenthesis_closer']) === false) {
374
            // Not a function call.
375
            return;
376
        }
377
378
        // Find the previous non-empty token.
379
        $search   = PHP_CodeSniffer_Tokens::$emptyTokens;
380
        $search[] = T_BITWISE_AND;
381
        $previous = $phpcsFile->findPrevious($search, ($stackPtr - 1), null, true);
382
        if ($tokens[$previous]['code'] === T_FUNCTION) {
383
            // It's a function definition, not a function call.
384
            return;
385
        }
386
387
        if ($tokens[$previous]['code'] === T_NEW) {
388
            // We are creating an object, not calling a function.
389
            return;
390
        }
391
392
        if ( $tokens[$previous]['code'] === T_OBJECT_OPERATOR ) {
393
            // We are calling a method of an object
394
            return;
395
        }
396
397
        if($this->isWhiteListed(strtolower($tokens[$stackPtr]['content'])) === true){
398
            // Function is whitelisted.
399
            return;
400
        }
401
402
        foreach ($this->removedExtensions as $extension => $versionList) {
403
            if (strpos(strtolower($tokens[$stackPtr]['content']), strtolower($extension)) === 0) {
404
                $error = '';
405
                $isErrored = false;
406
                $isDeprecated = false;
407
                foreach ($versionList as $version => $status) {
408
                    if ($version != 'alternative') {
409
                        if ($status == -1 || $status == 0) {
410
                            if ($this->supportsAbove($version)) {
411
                                switch ($status) {
412
                                    case -1:
413
                                        if($isDeprecated === false ) {
414
                                            $error .= 'deprecated since PHP ' . $version . ' and ';
415
                                            $isDeprecated = true;
416
                                        }
417
                                        break;
418
                                    case 0:
419
                                        $isErrored = true;
420
                                        $error .= 'removed since PHP ' . $version . ' and ';
421
                                        break 2;
422
                                }
423
                            }
424
                        }
425
                    }
426
                }
427
                if (strlen($error) > 0) {
428
                    $error = "Extension '" . $extension . "' is " . $error;
429
                    $error = substr($error, 0, strlen($error) - 5);
430
                    if (!is_null($versionList['alternative'])) {
431
                        $error .= ' - use ' . $versionList['alternative'] . ' instead.';
432
                    }
433
                    if ($isErrored === true) {
434
                        $phpcsFile->addError($error, $stackPtr);
435
                    } else {
436
                        $phpcsFile->addWarning($error, $stackPtr);
437
                    }
438
                }
439
            }
440
        }
441
442
    }//end process()
443
444
    /**
445
     * Is the current function being checked whitelisted ?
446
     *
447
     * Parsing the list late as it may be provided as a property, but also inline.
448
     *
449
     * @param string $content Content of the current token.
450
     *
451
     * @return bool
452
     */
453
    protected function isWhiteListed($content) {
454
        if (isset($this->functionWhitelist) === false) {
455
            return false;
456
        }
457
458
        if (is_string($this->functionWhitelist) === true) {
459
            if (strpos($this->functionWhitelist, ',') !== false) {
460
                $this->functionWhitelist = explode(',', $this->functionWhitelist);
461
            } else {
462
                $this->functionWhitelist = (array) $this->functionWhitelist;
463
            }
464
        }
465
466
        if (is_array($this->functionWhitelist) === true) {
467
            $this->functionWhitelist = array_map('strtolower',$this->functionWhitelist);
468
            return in_array($content, $this->functionWhitelist, true);
469
        }
470
471
        return false;
472
473
    }//end isWhiteListed()
474
475
}//end class
476