Completed
Push — master ( da65dc...5751ed )
by Tomáš
20:43 queued 16:49
created

Fixer   D

Complexity

Total Complexity 82

Size/Duplication

Total Lines 698
Duplicated Lines 11.03 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 77
loc 698
rs 4.0494
c 0
b 0
f 0
wmc 82
lcom 1
cbo 3

16 Methods

Rating   Name   Duplication   Size   Complexity  
A startFile() 0 17 3
B generateDiff() 0 55 9
A getFixCount() 0 5 1
A getContents() 0 6 1
A getTokenContent() 0 11 3
A beginChangeset() 0 20 3
A substrToken() 0 13 2
A addNewline() 0 6 1
A addNewlineBefore() 0 6 1
A addContent() 0 6 1
A addContentBefore() 0 6 1
C fixFile() 9 77 14
C endChangeset() 6 40 8
B rollbackChangeset() 0 28 4
D replaceToken() 31 117 22
C revertToken() 31 46 8

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Fixer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Fixer, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * A helper class for fixing errors.
4
 *
5
 * Provides helper functions that act upon a token array and modify the file
6
 * content.
7
 *
8
 * @author    Greg Sherwood <[email protected]>
9
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
10
 * @license   https://github.com/squizlabs/Symplify\PHP7_CodeSniffer/blob/master/licence.txt BSD Licence
11
 */
12
13
namespace Symplify\PHP7_CodeSniffer;
14
15
use Symplify\PHP7_CodeSniffer\Files\File;
16
use Symplify\PHP7_CodeSniffer\Util\Common;
17
18
class Fixer
19
{
20
21
    /**
22
     * Is the fixer enabled and fixing a file?
23
     *
24
     * Sniffs should check this value to ensure they are not
25
     * doing extra processing to prepare for a fix when fixing is
26
     * not required.
27
     *
28
     * @var boolean
29
     */
30
    public $enabled = false;
31
32
    /**
33
     * The number of times we have looped over a file.
34
     *
35
     * @var integer
36
     */
37
    public $loops = 0;
38
39
    /**
40
     * The file being fixed.
41
     *
42
     * @var \Symplify\PHP7_CodeSniffer\Files\File
43
     */
44
    private $currentFile = null;
45
46
    /**
47
     * The list of tokens that make up the file contents.
48
     *
49
     * This is a simplified list which just contains the token content and nothing
50
     * else. This is the array that is updated as fixes are made, not the file's
51
     * token array. Imploding this array will give you the file content back.
52
     *
53
     * @var array<int, string>
54
     */
55
    private $_tokens = array();
56
57
    /**
58
     * A list of tokens that have already been fixed.
59
     *
60
     * We don't allow the same token to be fixed more than once each time
61
     * through a file as this can easily cause conflicts between sniffs.
62
     *
63
     * @var int[]
64
     */
65
    private $_fixedTokens = array();
66
67
    /**
68
     * The last value of each fixed token.
69
     *
70
     * If a token is being "fixed" back to its last value, the fix is
71
     * probably conflicting with another.
72
     *
73
     * @var array<int, string>
74
     */
75
    private $_oldTokenValues = array();
76
77
    /**
78
     * A list of tokens that have been fixed during a changeset.
79
     *
80
     * All changes in changeset must be able to be applied, or else
81
     * the entire changeset is rejected.
82
     *
83
     * @var array
84
     */
85
    private $_changeset = array();
86
87
    /**
88
     * Is there an open changeset.
89
     *
90
     * @var boolean
91
     */
92
    private $_inChangeset = false;
93
94
    /**
95
     * Is the current fixing loop in conflict?
96
     *
97
     * @var boolean
98
     */
99
    private $_inConflict = false;
100
101
    /**
102
     * The number of fixes that have been performed.
103
     *
104
     * @var integer
105
     */
106
    private $_numFixes = 0;
107
108
109
    /**
110
     * Starts fixing a new file.
111
     *
112
     * @param \Symplify\PHP7_CodeSniffer\Files\File $phpcsFile The file being fixed.
113
     *
114
     * @return void
115
     */
116
    public function startFile(File $phpcsFile)
117
    {
118
        $this->currentFile  = $phpcsFile;
119
        $this->_numFixes    = 0;
120
        $this->_fixedTokens = array();
121
122
        $tokens        = $phpcsFile->getTokens();
123
        $this->_tokens = array();
124
        foreach ($tokens as $index => $token) {
125
            if (isset($token['orig_content']) === true) {
126
                $this->_tokens[$index] = $token['orig_content'];
127
            } else {
128
                $this->_tokens[$index] = $token['content'];
129
            }
130
        }
131
132
    }//end startFile()
133
134
135
    /**
136
     * Attempt to fix the file by processing it until no fixes are made.
137
     *
138
     * @return boolean
139
     */
140
    public function fixFile()
141
    {
142
        $fixable = $this->currentFile->getFixableCount();
143
        if ($fixable === 0) {
144
            // Nothing to fix.
145
            return false;
146
        }
147
148
        $stdin = false;
149
        if (empty($this->currentFile->config->files) === true) {
0 ignored issues
show
Documentation introduced by
The property files does not exist on object<Symplify\PHP7_CodeSniffer\Config>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
150
            $stdin = true;
151
        }
152
153
        $this->enabled = true;
154
155
        $this->loops = 0;
156
        while ($this->loops < 50) {
157
            ob_start();
158
159
            // Only needed once file content has changed.
160
            $contents = $this->getContents();
161
162
            if (PHP_CodeSniffer_VERBOSITY > 2) {
163
                @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
164
                echo '---START FILE CONTENT---'.PHP_EOL;
165
                $lines = explode($this->currentFile->eolChar, $contents);
166
                $max   = strlen(count($lines));
167
                foreach ($lines as $lineNum => $line) {
168
                    $lineNum++;
169
                    echo str_pad($lineNum, $max, ' ', STR_PAD_LEFT).'|'.$line.PHP_EOL;
170
                }
171
172
                echo '--- END FILE CONTENT ---'.PHP_EOL;
173
                ob_start();
174
            }
175
176
            $this->_inConflict = false;
177
            $this->currentFile->ruleset->populateTokenListeners();
178
            $this->currentFile->setContent($contents);
179
            $this->currentFile->process();
180
            ob_end_clean();
181
182
            $this->loops++;
183
184
            if (PHP_CodeSniffer_CBF === true && $stdin === false) {
185
                echo "\r".str_repeat(' ', 80)."\r";
186
                echo "\t=> Fixing file: $this->_numFixes/$fixable violations remaining [made $this->loops pass";
187
                if ($this->loops > 1) {
188
                    echo 'es';
189
                }
190
191
                echo ']... ';
192
            }
193
194
            if ($this->_numFixes === 0 && $this->_inConflict === false) {
195
                // Nothing left to do.
196
                break;
197
            } else if (PHP_CodeSniffer_VERBOSITY > 1) {
198
                echo "\t* fixed $this->_numFixes violations, starting loop ".($this->loops + 1).' *'.PHP_EOL;
199
            }
200
        }//end while
201
202
        $this->enabled = false;
203
204 View Code Duplication
        if ($this->_numFixes > 0) {
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...
205
            if (PHP_CodeSniffer_VERBOSITY > 1) {
206
                @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
207
                echo "\t*** Reached maximum number of loops with $this->_numFixes violations left unfixed ***".PHP_EOL;
208
                ob_start();
209
            }
210
211
            return false;
212
        }
213
214
        return true;
215
216
    }//end fixFile()
217
218
219
    /**
220
     * Generates a text diff of the original file and the new content.
221
     *
222
     * @param string  $filePath Optional file path to diff the file against.
223
     *                          If not specified, the original version of the
224
     *                          file will be used.
225
     * @param boolean $colors   Print colored output or not.
226
     *
227
     * @return string
228
     */
229
    public function generateDiff($filePath=null, $colors=true)
230
    {
231
        if ($filePath === null) {
232
            $filePath = $this->currentFile->getFilename();
233
        }
234
235
        $cwd      = getcwd().DIRECTORY_SEPARATOR;
236
        $filename = str_replace($cwd, '', $filePath);
237
        $contents = $this->getContents();
238
239
        $tempName  = tempnam(sys_get_temp_dir(), 'phpcs-fixer');
240
        $fixedFile = fopen($tempName, 'w');
241
        fwrite($fixedFile, $contents);
242
243
        // We must use something like shell_exec() because whitespace at the end
244
        // of lines is critical to diff files.
245
        $cmd  = "diff -u -L\"$filename\" -LSymplify\PHP7_CodeSniffer \"$filename\" \"$tempName\"";
246
        $diff = shell_exec($cmd);
247
248
        fclose($fixedFile);
249
        if (is_file($tempName) === true) {
250
            unlink($tempName);
251
        }
252
253
        if ($colors === false) {
254
            return $diff;
255
        }
256
257
        $diffLines = explode(PHP_EOL, $diff);
258
        if (count($diffLines) === 1) {
259
            // Seems to be required for cygwin.
260
            $diffLines = explode("\n", $diff);
261
        }
262
263
        $diff = array();
264
        foreach ($diffLines as $line) {
265
            if (isset($line[0]) === true) {
266
                switch ($line[0]) {
267
                case '-':
268
                    $diff[] = "\033[31m$line\033[0m";
269
                    break;
270
                case '+':
271
                    $diff[] = "\033[32m$line\033[0m";
272
                    break;
273
                default:
274
                    $diff[] = $line;
275
                }
276
            }
277
        }
278
279
        $diff = implode(PHP_EOL, $diff);
280
281
        return $diff;
282
283
    }//end generateDiff()
284
285
286
    /**
287
     * Get a count of fixes that have been performed on the file.
288
     *
289
     * This value is reset every time a new file is started, or an existing
290
     * file is restarted.
291
     *
292
     * @return int
293
     */
294
    public function getFixCount()
295
    {
296
        return $this->_numFixes;
297
298
    }//end getFixCount()
299
300
301
    /**
302
     * Get the current content of the file, as a string.
303
     *
304
     * @return string
305
     */
306
    public function getContents()
307
    {
308
        $contents = implode($this->_tokens);
309
        return $contents;
310
311
    }//end getContents()
312
313
314
    /**
315
     * Get the current fixed content of a token.
316
     *
317
     * This function takes changesets into account so should be used
318
     * instead of directly accessing the token array.
319
     *
320
     * @param int $stackPtr The position of the token in the token stack.
321
     *
322
     * @return string
323
     */
324
    public function getTokenContent($stackPtr)
325
    {
326
        if ($this->_inChangeset === true
327
            && isset($this->_changeset[$stackPtr]) === true
328
        ) {
329
            return $this->_changeset[$stackPtr];
330
        } else {
331
            return $this->_tokens[$stackPtr];
332
        }
333
334
    }//end getTokenContent()
335
336
337
    /**
338
     * Start recording actions for a changeset.
339
     *
340
     * @return void
341
     */
342
    public function beginChangeset()
343
    {
344
        if ($this->_inConflict === true) {
345
            return false;
346
        }
347
348
        if (PHP_CodeSniffer_VERBOSITY > 1) {
349
            $bt    = debug_backtrace();
350
            $sniff = $bt[1]['class'];
351
            $line  = $bt[0]['line'];
352
353
            @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
354
            echo "\t=> Changeset started by $sniff (line $line)".PHP_EOL;
355
            ob_start();
356
        }
357
358
        $this->_changeset   = array();
359
        $this->_inChangeset = true;
360
361
    }//end beginChangeset()
362
363
364
    /**
365
     * Stop recording actions for a changeset, and apply logged changes.
366
     *
367
     * @return boolean
368
     */
369
    public function endChangeset()
370
    {
371
        if ($this->_inConflict === true) {
372
            return false;
373
        }
374
375
        $this->_inChangeset = false;
376
377
        $success = true;
378
        $applied = array();
379
        foreach ($this->_changeset as $stackPtr => $content) {
380
            $success = $this->replaceToken($stackPtr, $content);
381
            if ($success === false) {
382
                break;
383
            } else {
384
                $applied[] = $stackPtr;
385
            }
386
        }
387
388
        if ($success === false) {
389
            // Rolling back all changes.
390
            foreach ($applied as $stackPtr) {
391
                $this->revertToken($stackPtr);
392
            }
393
394
            if (PHP_CodeSniffer_VERBOSITY > 1) {
395
                @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
396
                echo "\t=> Changeset failed to apply".PHP_EOL;
397
                ob_start();
398
            }
399 View Code Duplication
        } else if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
400
            $fixes = count($this->_changeset);
401
            @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
402
            echo "\t=> Changeset ended: $fixes changes applied".PHP_EOL;
403
            ob_start();
404
        }
405
406
        $this->_changeset = array();
407
408
    }//end endChangeset()
409
410
411
    /**
412
     * Stop recording actions for a changeset, and discard logged changes.
413
     *
414
     * @return void
415
     */
416
    public function rollbackChangeset()
417
    {
418
        $this->_inChangeset = false;
419
        $this->_inConflict  = false;
420
421
        if (empty($this->_changeset) === false) {
422
            if (PHP_CodeSniffer_VERBOSITY > 1) {
423
                $bt = debug_backtrace();
424
                if ($bt[1]['class'] === 'Symplify\PHP7_CodeSniffer_Fixer') {
425
                    $sniff = $bt[2]['class'];
426
                    $line  = $bt[1]['line'];
427
                } else {
428
                    $sniff = $bt[1]['class'];
429
                    $line  = $bt[0]['line'];
430
                }
431
432
                $numChanges = count($this->_changeset);
433
434
                @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
435
                echo "\t\tR: $sniff (line $line) rolled back the changeset ($numChanges changes)".PHP_EOL;
436
                echo "\t=> Changeset rolled back".PHP_EOL;
437
                ob_start();
438
            }
439
440
            $this->_changeset = array();
441
        }//end if
442
443
    }//end rollbackChangeset()
444
445
446
    /**
447
     * Replace the entire contents of a token.
448
     *
449
     * @param int    $stackPtr The position of the token in the token stack.
450
     * @param string $content  The new content of the token.
451
     *
452
     * @return bool If the change was accepted.
453
     */
454
    public function replaceToken($stackPtr, $content)
455
    {
456
        if ($this->_inConflict === true) {
457
            return false;
458
        }
459
460
        if ($this->_inChangeset === false
461
            && isset($this->_fixedTokens[$stackPtr]) === true
462
        ) {
463
            $indent = "\t";
464
            if (empty($this->_changeset) === false) {
465
                $indent .= "\t";
466
            }
467
468
            if (PHP_CodeSniffer_VERBOSITY > 1) {
469
                @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
470
                echo "$indent* token $stackPtr has already been modified, skipping *".PHP_EOL;
471
                ob_start();
472
            }
473
474
            return false;
475
        }
476
477 View Code Duplication
        if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
478
            $bt = debug_backtrace();
479
            if ($bt[1]['class'] === 'Symplify\PHP7_CodeSniffer_Fixer') {
480
                $sniff = $bt[2]['class'];
481
                $line  = $bt[1]['line'];
482
            } else {
483
                $sniff = $bt[1]['class'];
484
                $line  = $bt[0]['line'];
485
            }
486
487
            $tokens     = $this->currentFile->getTokens();
488
            $type       = $tokens[$stackPtr]['type'];
489
            $oldContent = Common::prepareForOutput($this->_tokens[$stackPtr]);
490
            $newContent = Common::prepareForOutput($content);
491
            if (trim($this->_tokens[$stackPtr]) === '' && isset($this->_tokens[($stackPtr + 1)]) === true) {
492
                // Add some context for whitespace only changes.
493
                $append      = Common::prepareForOutput($this->_tokens[($stackPtr + 1)]);
494
                $oldContent .= $append;
495
                $newContent .= $append;
496
            }
497
        }//end if
498
499
        if ($this->_inChangeset === true) {
500
            $this->_changeset[$stackPtr] = $content;
501
502
            if (PHP_CodeSniffer_VERBOSITY > 1) {
503
                @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
504
                echo "\t\tQ: $sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
0 ignored issues
show
Bug introduced by
The variable $sniff does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $line does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $type does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $oldContent does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $newContent does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
505
                ob_start();
506
            }
507
508
            return true;
509
        }
510
511
        if (isset($this->_oldTokenValues[$stackPtr]) === false) {
512
            $this->_oldTokenValues[$stackPtr] = array(
513
                                                 'curr' => $content,
514
                                                 'prev' => $this->_tokens[$stackPtr],
515
                                                 'loop' => $this->loops,
516
                                                );
517
        } else {
518
            if ($this->_oldTokenValues[$stackPtr]['prev'] === $content
519
                && $this->_oldTokenValues[$stackPtr]['loop'] === ($this->loops - 1)
520
            ) {
521
                if (PHP_CodeSniffer_VERBOSITY > 1) {
522
                    $indent = "\t";
523
                    if (empty($this->_changeset) === false) {
524
                        $indent .= "\t";
525
                    }
526
527
                    $loop = $this->_oldTokenValues[$stackPtr]['loop'];
528
529
                    @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
530
                    echo "$indent**** $sniff (line $line) has possible conflict with another sniff on loop $loop; caused by the following change ****".PHP_EOL;
531
                    echo "$indent**** replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\" ****".PHP_EOL;
532
                }
533
534
                if ($this->_oldTokenValues[$stackPtr]['loop'] >= ($this->loops - 1)) {
535
                    $this->_inConflict = true;
536
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
537
                        echo "$indent**** ignoring all changes until next loop ****".PHP_EOL;
0 ignored issues
show
Bug introduced by
The variable $indent does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
538
                    }
539
                }
540
541
                if (PHP_CodeSniffer_VERBOSITY > 1) {
542
                    ob_start();
543
                }
544
545
                return false;
546
            }//end if
547
548
            $this->_oldTokenValues[$stackPtr]['prev'] = $this->_oldTokenValues[$stackPtr]['curr'];
549
            $this->_oldTokenValues[$stackPtr]['curr'] = $content;
550
            $this->_oldTokenValues[$stackPtr]['loop'] = $this->loops;
551
        }//end if
552
553
        $this->_fixedTokens[$stackPtr] = $this->_tokens[$stackPtr];
554
        $this->_tokens[$stackPtr]      = $content;
555
        $this->_numFixes++;
556
557 View Code Duplication
        if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
558
            $indent = "\t";
559
            if (empty($this->_changeset) === false) {
560
                $indent .= "\tA: ";
561
            }
562
563
            @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
564
            echo "$indent$sniff (line $line) replaced token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
565
            ob_start();
566
        }
567
568
        return true;
569
570
    }//end replaceToken()
571
572
573
    /**
574
     * Reverts the previous fix made to a token.
575
     *
576
     * @param int $stackPtr The position of the token in the token stack.
577
     *
578
     * @return bool If a change was reverted.
579
     */
580
    public function revertToken($stackPtr)
581
    {
582
        if (isset($this->_fixedTokens[$stackPtr]) === false) {
583
            return false;
584
        }
585
586 View Code Duplication
        if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
587
            $bt = debug_backtrace();
588
            if ($bt[1]['class'] === 'Symplify\PHP7_CodeSniffer_Fixer') {
589
                $sniff = $bt[2]['class'];
590
                $line  = $bt[1]['line'];
591
            } else {
592
                $sniff = $bt[1]['class'];
593
                $line  = $bt[0]['line'];
594
            }
595
596
            $tokens     = $this->currentFile->getTokens();
597
            $type       = $tokens[$stackPtr]['type'];
598
            $oldContent = Common::prepareForOutput($this->_tokens[$stackPtr]);
599
            $newContent = Common::prepareForOutput($this->_fixedTokens[$stackPtr]);
600
            if (trim($this->_tokens[$stackPtr]) === '' && isset($tokens[($stackPtr + 1)]) === true) {
601
                // Add some context for whitespace only changes.
602
                $append      = Common::prepareForOutput($this->_tokens[($stackPtr + 1)]);
603
                $oldContent .= $append;
604
                $newContent .= $append;
605
            }
606
        }//end if
607
608
        $this->_tokens[$stackPtr] = $this->_fixedTokens[$stackPtr];
609
        unset($this->_fixedTokens[$stackPtr]);
610
        $this->_numFixes--;
611
612 View Code Duplication
        if (PHP_CodeSniffer_VERBOSITY > 1) {
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...
613
            $indent = "\t";
614
            if (empty($this->_changeset) === false) {
615
                $indent .= "\tR: ";
616
            }
617
618
            @ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
619
            echo "$indent$sniff (line $line) reverted token $stackPtr ($type) \"$oldContent\" => \"$newContent\"".PHP_EOL;
0 ignored issues
show
Bug introduced by
The variable $sniff does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $line does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $type does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $oldContent does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $newContent does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
620
            ob_start();
621
        }
622
623
        return true;
624
625
    }//end revertToken()
626
627
628
    /**
629
     * Replace the content of a token with a part of its current content.
630
     *
631
     * @param int $stackPtr The position of the token in the token stack.
632
     * @param int $start    The first character to keep.
633
     * @param int $length   The number of chacters to keep. If NULL, the content of
634
     *                      the token from $start to the end of the content is kept.
635
     *
636
     * @return bool If the change was accepted.
637
     */
638
    public function substrToken($stackPtr, $start, $length=null)
639
    {
640
        $current = $this->getTokenContent($stackPtr);
641
642
        if ($length === null) {
643
            $newContent = substr($current, $start);
644
        } else {
645
            $newContent = substr($current, $start, $length);
646
        }
647
648
        return $this->replaceToken($stackPtr, $newContent);
649
650
    }//end substrToken()
651
652
653
    /**
654
     * Adds a newline to end of a token's content.
655
     *
656
     * @param int $stackPtr The position of the token in the token stack.
657
     *
658
     * @return bool If the change was accepted.
659
     */
660
    public function addNewline($stackPtr)
661
    {
662
        $current = $this->getTokenContent($stackPtr);
663
        return $this->replaceToken($stackPtr, $current.$this->currentFile->eolChar);
664
665
    }//end addNewline()
666
667
668
    /**
669
     * Adds a newline to the start of a token's content.
670
     *
671
     * @param int $stackPtr The position of the token in the token stack.
672
     *
673
     * @return bool If the change was accepted.
674
     */
675
    public function addNewlineBefore($stackPtr)
676
    {
677
        $current = $this->getTokenContent($stackPtr);
678
        return $this->replaceToken($stackPtr, $this->currentFile->eolChar.$current);
679
680
    }//end addNewlineBefore()
681
682
683
    /**
684
     * Adds content to the end of a token's current content.
685
     *
686
     * @param int    $stackPtr The position of the token in the token stack.
687
     * @param string $content  The content to add.
688
     *
689
     * @return bool If the change was accepted.
690
     */
691
    public function addContent($stackPtr, $content)
692
    {
693
        $current = $this->getTokenContent($stackPtr);
694
        return $this->replaceToken($stackPtr, $current.$content);
695
696
    }//end addContent()
697
698
699
    /**
700
     * Adds content to the start of a token's current content.
701
     *
702
     * @param int    $stackPtr The position of the token in the token stack.
703
     * @param string $content  The content to add.
704
     *
705
     * @return bool If the change was accepted.
706
     */
707
    public function addContentBefore($stackPtr, $content)
708
    {
709
        $current = $this->getTokenContent($stackPtr);
710
        return $this->replaceToken($stackPtr, $content.$current);
711
712
    }//end addContentBefore()
713
714
715
}//end class
716