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

Tokenizer::replaceTabsInToken()   C

Complexity

Conditions 12
Paths 24

Size

Total Lines 82
Code Lines 48

Duplication

Lines 3
Ratio 3.66 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 3
loc 82
rs 5.034
cc 12
eloc 48
nc 24
nop 3

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
 * The base tokenizer class.
4
 *
5
 * @author    Greg Sherwood <[email protected]>
6
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
7
 * @license   https://github.com/squizlabs/Symplify\PHP7_CodeSniffer/blob/master/licence.txt BSD Licence
8
 */
9
10
namespace Symplify\PHP7_CodeSniffer\Tokenizers;
11
12
use Symplify\PHP7_CodeSniffer\RuntimeException;
13
use Symplify\PHP7_CodeSniffer\Util;
14
15
abstract class Tokenizer
16
{
17
18
    /**
19
     * The config data for the run.
20
     *
21
     * @var \Symplify\PHP7_CodeSniffer\Config
22
     */
23
    protected $config = null;
24
25
    /**
26
     * The EOL char used in the content.
27
     *
28
     * @var string
29
     */
30
    protected $eolChar = array();
31
32
    /**
33
     * A token-based representation of the content.
34
     *
35
     * @var array
36
     */
37
    protected $tokens = array();
38
39
    /**
40
     * Known lengths of tokens.
41
     *
42
     * @var array<int, int>
43
     */
44
    public $knownLengths = array();
45
46
    /**
47
     * A list of lines being ignored due to error suppression comments.
48
     *
49
     * @var array
50
     */
51
    public $ignoredLines = array();
52
53
54
    /**
55
     * Initialise and run the tokenizer.
56
     *
57
     * @param string                         $content The content to tokenize,
58
     * @param \Symplify\PHP7_CodeSniffer\Config | null $config  The config data for the run.
59
     * @param string                         $eolChar The EOL char used in the content.
60
     *
61
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
62
     * @throws TokenizerException If the file appears to be minified.
63
     */
64
    public function __construct($content, $config, $eolChar='\n')
65
    {
66
        $this->eolChar = $eolChar;
67
68
        $this->config = $config;
69
        $this->tokens = $this->tokenize($content);
70
71
        if ($config === null) {
72
            return;
73
        }
74
75
        $this->createPositionMap();
76
        $this->createTokenMap();
77
        $this->createParenthesisNestingMap();
78
        $this->createScopeMap();
79
        $this->createLevelMap();
80
81
        // Allow the tokenizer to do additional processing if required.
82
        $this->processAdditional();
83
84
    }//end __construct()
85
86
87
    /**
88
     * Checks the content to see if it looks minified.
89
     *
90
     * @param string $content The content to tokenize,
91
     * @param string $eolChar The EOL char used in the content.
92
     *
93
     * @return boolean
94
     */
95
    protected function isMinifiedContent($content, $eolChar='\n')
96
    {
97
        // Minified files often have a very large number of characters per line
98
        // and cause issues when tokenizing.
99
        $numChars = strlen($content);
100
        $numLines = (substr_count($content, $eolChar) + 1);
101
        $average  = ($numChars / $numLines);
102
        if ($average > 100) {
103
            return true;
104
        }
105
106
        return false;
107
108
    }//end isMinifiedContent()
109
110
111
    /**
112
     * Gets the array of tokens.
113
     *
114
     * @return array
115
     */
116
    public function getTokens()
117
    {
118
        return $this->tokens;
119
120
    }//end getTokens()
121
122
123
    /**
124
     * Creates an array of tokens when given some content.
125
     *
126
     * @param string $string The string to tokenize.
127
     *
128
     * @return array
129
     */
130
    abstract protected function tokenize($string);
131
132
133
    /**
134
     * Performs additional processing after main tokenizing.
135
     *
136
     * @return void
137
     */
138
    abstract protected function processAdditional();
139
140
141
    /**
142
     * Sets token position information.
143
     *
144
     * Can also convert tabs into spaces. Each tab can represent between
145
     * 1 and $width spaces, so this cannot be a straight string replace.
146
     *
147
     * @return void
148
     */
149
    private function createPositionMap()
150
    {
151
        $currColumn = 1;
152
        $lineNumber = 1;
153
        $eolLen     = (strlen($this->eolChar) * -1);
154
        $ignoring   = false;
155
        $inTests    = defined('Symplify\PHP7_CodeSniffer_IN_TESTS');
156
157
        $checkEncoding = false;
158 View Code Duplication
        if ($this->config->encoding !== 'iso-8859-1' && function_exists('iconv_strlen') === true) {
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...
Documentation introduced by
The property encoding 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...
159
            $checkEncoding = true;
160
        }
161
162
        $this->tokensWithTabs = array(
0 ignored issues
show
Bug introduced by
The property tokensWithTabs does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
163
                                 T_WHITESPACE               => true,
164
                                 T_COMMENT                  => true,
165
                                 T_DOC_COMMENT              => true,
166
                                 T_DOC_COMMENT_WHITESPACE   => true,
167
                                 T_DOC_COMMENT_STRING       => true,
168
                                 T_CONSTANT_ENCAPSED_STRING => true,
169
                                 T_DOUBLE_QUOTED_STRING     => true,
170
                                 T_HEREDOC                  => true,
171
                                 T_NOWDOC                   => true,
172
                                 T_INLINE_HTML              => true,
173
                                );
174
175
        $this->numTokens = count($this->tokens);
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
176
        for ($i = 0; $i < $this->numTokens; $i++) {
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
177
            $this->tokens[$i]['line']   = $lineNumber;
178
            $this->tokens[$i]['column'] = $currColumn;
179
180
            if (isset($this->knownLengths[$this->tokens[$i]['code']]) === true) {
181
                // There are no tabs in the tokens we know the length of.
182
                $length      = $this->knownLengths[$this->tokens[$i]['code']];
183
                $currColumn += $length;
184
            } else if ($this->config->tabWidth === 0
0 ignored issues
show
Documentation introduced by
The property tabWidth 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...
185
                || isset($this->tokensWithTabs[$this->tokens[$i]['code']]) === false
0 ignored issues
show
Bug introduced by
The property tokensWithTabs does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
186
                || strpos($this->tokens[$i]['content'], "\t") === false
187
            ) {
188
                // There are no tabs in this content, or we aren't replacing them.
189
                if ($checkEncoding === true) {
190
                    // Not using the default encoding, so take a bit more care.
191
                    $length = @iconv_strlen($this->tokens[$i]['content'], $this->config->encoding);
0 ignored issues
show
Documentation introduced by
The property encoding 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...
192
                    if ($length === false) {
193
                        // String contained invalid characters, so revert to default.
194
                        $length = strlen($this->tokens[$i]['content']);
195
                    }
196
                } else {
197
                    $length = strlen($this->tokens[$i]['content']);
198
                }
199
200
                $currColumn += $length;
201
            } else {
202
                $this->replaceTabsInToken($this->tokens[$i]);
203
                $length      = $this->tokens[$i]['length'];
204
                $currColumn += $length;
205
            }//end if
206
207
            $this->tokens[$i]['length'] = $length;
208
209
            if (isset($this->knownLengths[$this->tokens[$i]['code']]) === false
210
                && strpos($this->tokens[$i]['content'], $this->eolChar) !== false
211
            ) {
212
                $lineNumber++;
213
                $currColumn = 1;
214
215
                // Newline chars are not counted in the token length.
216
                $this->tokens[$i]['length'] += $eolLen;
217
            }
218
219
            if ($this->tokens[$i]['code'] === T_COMMENT
220
                || $this->tokens[$i]['code'] === T_DOC_COMMENT_TAG
221
                || ($inTests === true && $this->tokens[$i]['code'] === T_INLINE_HTML)
222
            ) {
223
                if (strpos($this->tokens[$i]['content'], '@codingStandards') !== false) {
224
                    if ($ignoring === false
225
                        && strpos($this->tokens[$i]['content'], '@codingStandardsIgnoreStart') !== false
226
                    ) {
227
                        $ignoring = true;
228
                    } else if ($ignoring === true
229
                        && strpos($this->tokens[$i]['content'], '@codingStandardsIgnoreEnd') !== false
230
                    ) {
231
                        $ignoring = false;
232
                        // Ignore this comment too.
233
                        $this->ignoredLines[$this->tokens[$i]['line']] = true;
234
                    } else if ($ignoring === false
235
                        && strpos($this->tokens[$i]['content'], '@codingStandardsIgnoreLine') !== false
236
                    ) {
237
                        $this->ignoredLines[($this->tokens[$i]['line'] + 1)] = true;
238
                        // Ignore this comment too.
239
                        $this->ignoredLines[$this->tokens[$i]['line']] = true;
240
                    }
241
                }
242
            }//end if
243
244
            if ($ignoring === true) {
245
                $this->ignoredLines[$this->tokens[$i]['line']] = true;
246
            }
247
        }//end for
248
249
    }//end createPositionMap()
250
251
252
    /**
253
     * Replaces tabs in original token content with spaces.
254
     *
255
     * Each tab can represent between 1 and $config->tabWidth spaces,
256
     * so this cannot be a straight string replace. The original content
257
     * is placed into an orig_content index and the new token length is also
258
     * set in the length index.
259
     *
260
     * @param array  $token   The token to replace tabs inside.
261
     * @param string $prefix  The character to use to represent the start of a tab.
262
     * @param string $padding The character to use to represent the end of a tab.
263
     *
264
     * @return void
265
     */
266
    public function replaceTabsInToken(&$token, $prefix=' ', $padding=' ')
267
    {
268
        $checkEncoding = false;
269 View Code Duplication
        if ($this->config->encoding !== 'iso-8859-1' && function_exists('iconv_strlen') === true) {
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...
Documentation introduced by
The property encoding 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...
270
            $checkEncoding = true;
271
        }
272
273
        $currColumn = $token['column'];
274
        $tabWidth   = $this->config->tabWidth;
0 ignored issues
show
Documentation introduced by
The property tabWidth does not exist on object<Symplify\PHP7_CodeSniffer\Config>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
275
        if ($tabWidth === 0) {
276
            $tabWidth = 1;
277
        }
278
279
        if (str_replace("\t", '', $token['content']) === '') {
280
            // String only contains tabs, so we can shortcut the process.
281
            $numTabs = strlen($token['content']);
282
283
            $newContent   = '';
0 ignored issues
show
Unused Code introduced by
$newContent is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
284
            $firstTabSize = ($tabWidth - ($currColumn % $tabWidth) + 1);
285
            $length       = ($firstTabSize + ($tabWidth * ($numTabs - 1)));
286
            $currColumn  += $length;
287
            $newContent   = $prefix.str_repeat($padding, ($length - 1));
288
        } else {
289
            // We need to determine the length of each tab.
290
            $tabs = explode("\t", $token['content']);
291
292
            $numTabs    = (count($tabs) - 1);
293
            $tabNum     = 0;
294
            $newContent = '';
295
            $length     = 0;
296
297
            foreach ($tabs as $content) {
298
                if ($content !== '') {
299
                    $newContent .= $content;
300
                    if ($checkEncoding === true) {
301
                        // Not using the default encoding, so take a bit more care.
302
                        $contentLength = @iconv_strlen($content, $this->config->encoding);
0 ignored issues
show
Documentation introduced by
The property encoding 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...
303
                        if ($contentLength === false) {
304
                            // String contained invalid characters, so revert to default.
305
                            $contentLength = strlen($content);
306
                        }
307
                    } else {
308
                        $contentLength = strlen($content);
309
                    }
310
311
                    $currColumn += $contentLength;
312
                    $length     += $contentLength;
313
                }
314
315
                // The last piece of content does not have a tab after it.
316
                if ($tabNum === $numTabs) {
317
                    break;
318
                }
319
320
                // Process the tab that comes after the content.
321
                $lastCurrColumn = $currColumn;
322
                $tabNum++;
323
324
                // Move the pointer to the next tab stop.
325
                if (($currColumn % $tabWidth) === 0) {
326
                    // This is the first tab, and we are already at a
327
                    // tab stop, so this tab counts as a single space.
328
                    $currColumn++;
329
                } else {
330
                    $currColumn++;
331
                    while (($currColumn % $tabWidth) !== 0) {
332
                        $currColumn++;
333
                    }
334
335
                    $currColumn++;
336
                }
337
338
                $length     += ($currColumn - $lastCurrColumn);
339
                $newContent .= $prefix.str_repeat($padding, ($currColumn - $lastCurrColumn - 1));
340
            }//end foreach
341
        }//end if
342
343
        $token['orig_content'] = $token['content'];
344
        $token['content']      = $newContent;
345
        $token['length']       = $length;
346
347
    }//end replaceTabsInToken()
348
349
350
    /**
351
     * Creates a map of brackets positions.
352
     *
353
     * @return void
354
     */
355
    private function createTokenMap()
356
    {
357
        if (PHP_CodeSniffer_VERBOSITY > 1) {
358
            echo "\t*** START TOKEN MAP ***".PHP_EOL;
359
        }
360
361
        $squareOpeners   = array();
362
        $curlyOpeners    = array();
363
        $this->numTokens = count($this->tokens);
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
364
365
        $openers   = array();
366
        $openOwner = null;
367
368
        for ($i = 0; $i < $this->numTokens; $i++) {
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
369
            /*
370
                Parenthesis mapping.
371
            */
372
373
            if (isset(Util\Tokens::$parenthesisOpeners[$this->tokens[$i]['code']]) === true) {
374
                $this->tokens[$i]['parenthesis_opener'] = null;
375
                $this->tokens[$i]['parenthesis_closer'] = null;
376
                $this->tokens[$i]['parenthesis_owner']  = $i;
377
                $openOwner = $i;
378
            } else if ($this->tokens[$i]['code'] === T_OPEN_PARENTHESIS) {
379
                $openers[] = $i;
380
                $this->tokens[$i]['parenthesis_opener'] = $i;
381
                if ($openOwner !== null) {
382
                    $this->tokens[$openOwner]['parenthesis_opener'] = $i;
383
                    $this->tokens[$i]['parenthesis_owner']          = $openOwner;
384
                    $openOwner = null;
385
                }
386
            } else if ($this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS) {
387
                // Did we set an owner for this set of parenthesis?
388
                $numOpeners = count($openers);
389
                if ($numOpeners !== 0) {
390
                    $opener = array_pop($openers);
391
                    if (isset($this->tokens[$opener]['parenthesis_owner']) === true) {
392
                        $owner = $this->tokens[$opener]['parenthesis_owner'];
393
394
                        $this->tokens[$owner]['parenthesis_closer'] = $i;
395
                        $this->tokens[$i]['parenthesis_owner']      = $owner;
396
                    }
397
398
                    $this->tokens[$i]['parenthesis_opener']      = $opener;
399
                    $this->tokens[$i]['parenthesis_closer']      = $i;
400
                    $this->tokens[$opener]['parenthesis_closer'] = $i;
401
                }
402
            }//end if
403
404
            /*
405
                Bracket mapping.
406
            */
407
408
            switch ($this->tokens[$i]['code']) {
409
            case T_OPEN_SQUARE_BRACKET:
410
                $squareOpeners[] = $i;
411
412 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...
413
                    echo str_repeat("\t", count($squareOpeners));
414
                    echo str_repeat("\t", count($curlyOpeners));
415
                    echo "=> Found square bracket opener at $i".PHP_EOL;
416
                }
417
                break;
418
            case T_OPEN_CURLY_BRACKET:
419
                if (isset($this->tokens[$i]['scope_closer']) === false) {
420
                    $curlyOpeners[] = $i;
421
422 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...
423
                        echo str_repeat("\t", count($squareOpeners));
424
                        echo str_repeat("\t", count($curlyOpeners));
425
                        echo "=> Found curly bracket opener at $i".PHP_EOL;
426
                    }
427
                }
428
                break;
429
            case T_CLOSE_SQUARE_BRACKET:
430
                if (empty($squareOpeners) === false) {
431
                    $opener = array_pop($squareOpeners);
432
                    $this->tokens[$i]['bracket_opener']      = $opener;
433
                    $this->tokens[$i]['bracket_closer']      = $i;
434
                    $this->tokens[$opener]['bracket_opener'] = $opener;
435
                    $this->tokens[$opener]['bracket_closer'] = $i;
436
437 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...
438
                        echo str_repeat("\t", count($squareOpeners));
439
                        echo str_repeat("\t", count($curlyOpeners));
440
                        echo "\t=> Found square bracket closer at $i for $opener".PHP_EOL;
441
                    }
442
                }
443
                break;
444
            case T_CLOSE_CURLY_BRACKET:
445
                if (empty($curlyOpeners) === false
446
                    && isset($this->tokens[$i]['scope_opener']) === false
447
                ) {
448
                    $opener = array_pop($curlyOpeners);
449
                    $this->tokens[$i]['bracket_opener']      = $opener;
450
                    $this->tokens[$i]['bracket_closer']      = $i;
451
                    $this->tokens[$opener]['bracket_opener'] = $opener;
452
                    $this->tokens[$opener]['bracket_closer'] = $i;
453
454 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...
455
                        echo str_repeat("\t", count($squareOpeners));
456
                        echo str_repeat("\t", count($curlyOpeners));
457
                        echo "\t=> Found curly bracket closer at $i for $opener".PHP_EOL;
458
                    }
459
                }
460
                break;
461
            default:
462
                continue;
463
            }//end switch
464
        }//end for
465
466
        // Cleanup for any openers that we didn't find closers for.
467
        // This typically means there was a syntax error breaking things.
468
        foreach ($openers as $opener) {
469
            unset($this->tokens[$opener]['parenthesis_opener']);
470
            unset($this->tokens[$opener]['parenthesis_owner']);
471
        }
472
473
        if (PHP_CodeSniffer_VERBOSITY > 1) {
474
            echo "\t*** END TOKEN MAP ***".PHP_EOL;
475
        }
476
477
    }//end createTokenMap()
478
479
480
    /**
481
     * Creates a map for the parenthesis tokens that surround other tokens.
482
     *
483
     * @return void
484
     */
485
    private function createParenthesisNestingMap()
486
    {
487
        $map = array();
488
        for ($i = 0; $i < $this->numTokens; $i++) {
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
489
            if (isset($this->tokens[$i]['parenthesis_opener']) === true
490
                && $i === $this->tokens[$i]['parenthesis_opener']
491
            ) {
492
                if (empty($map) === false) {
493
                    $this->tokens[$i]['nested_parenthesis'] = $map;
494
                }
495
496
                if (isset($this->tokens[$i]['parenthesis_closer']) === true) {
497
                    $map[$this->tokens[$i]['parenthesis_opener']]
498
                        = $this->tokens[$i]['parenthesis_closer'];
499
                }
500
            } else if (isset($this->tokens[$i]['parenthesis_closer']) === true
501
                && $i === $this->tokens[$i]['parenthesis_closer']
502
            ) {
503
                array_pop($map);
504
                if (empty($map) === false) {
505
                    $this->tokens[$i]['nested_parenthesis'] = $map;
506
                }
507
            } else {
508
                if (empty($map) === false) {
509
                    $this->tokens[$i]['nested_parenthesis'] = $map;
510
                }
511
            }//end if
512
        }//end for
513
514
    }//end createParenthesisNestingMap()
515
516
517
    /**
518
     * Creates a scope map of tokens that open scopes.
519
     *
520
     * @return void
521
     * @see    recurseScopeMap()
522
     */
523
    private function createScopeMap()
524
    {
525
        if (PHP_CodeSniffer_VERBOSITY > 1) {
526
            echo "\t*** START SCOPE MAP ***".PHP_EOL;
527
        }
528
529
        for ($i = 0; $i < $this->numTokens; $i++) {
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
530
            // Check to see if the current token starts a new scope.
531
            if (isset($this->scopeOpeners[$this->tokens[$i]['code']]) === true) {
0 ignored issues
show
Bug introduced by
The property scopeOpeners does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
532
                if (PHP_CodeSniffer_VERBOSITY > 1) {
533
                    $type    = $this->tokens[$i]['type'];
534
                    $content = Util\Common::prepareForOutput($this->tokens[$i]['content']);
535
                    echo "\tStart scope map at $i:$type => $content".PHP_EOL;
536
                }
537
538
                if (isset($this->tokens[$i]['scope_condition']) === true) {
539
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
540
                        echo "\t* already processed, skipping *".PHP_EOL;
541
                    }
542
543
                    continue;
544
                }
545
546
                $i = $this->recurseScopeMap($i);
547
            }//end if
548
        }//end for
549
550
        if (PHP_CodeSniffer_VERBOSITY > 1) {
551
            echo "\t*** END SCOPE MAP ***".PHP_EOL;
552
        }
553
554
    }//end createScopeMap()
555
556
557
    /**
558
     * Recurses though the scope openers to build a scope map.
559
     *
560
     * @param int $stackPtr The position in the stack of the token that
561
     *                      opened the scope (eg. an IF token or FOR token).
562
     * @param int $depth    How many scope levels down we are.
563
     * @param int $ignore   How many curly braces we are ignoring.
564
     *
565
     * @return int The position in the stack that closed the scope.
566
     */
567
    private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0)
568
    {
569
        if (PHP_CodeSniffer_VERBOSITY > 1) {
570
            echo str_repeat("\t", $depth);
571
            echo "=> Begin scope map recursion at token $stackPtr with depth $depth".PHP_EOL;
572
        }
573
574
        $opener    = null;
575
        $currType  = $this->tokens[$stackPtr]['code'];
576
        $startLine = $this->tokens[$stackPtr]['line'];
577
578
        // We will need this to restore the value if we end up
579
        // returning a token ID that causes our calling function to go back
580
        // over already ignored braces.
581
        $originalIgnore = $ignore;
582
583
        // If the start token for this scope opener is the same as
584
        // the scope token, we have already found our opener.
585
        if (isset($this->scopeOpeners[$currType]['start'][$currType]) === true) {
586
            $opener = $stackPtr;
587
        }
588
589
        for ($i = ($stackPtr + 1); $i < $this->numTokens; $i++) {
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
590
            $tokenType = $this->tokens[$i]['code'];
591
592
            if (PHP_CodeSniffer_VERBOSITY > 1) {
593
                $type    = $this->tokens[$i]['type'];
594
                $line    = $this->tokens[$i]['line'];
595
                $content = Util\Common::prepareForOutput($this->tokens[$i]['content']);
596
597
                echo str_repeat("\t", $depth);
598
                echo "Process token $i on line $line [";
599
                if ($opener !== null) {
600
                    echo "opener:$opener;";
601
                }
602
603
                if ($ignore > 0) {
604
                    echo "ignore=$ignore;";
605
                }
606
607
                echo "]: $type => $content".PHP_EOL;
608
            }//end if
609
610
            // Very special case for IF statements in PHP that can be defined without
611
            // scope tokens. E.g., if (1) 1; 1 ? (1 ? 1 : 1) : 1;
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
612
            // If an IF statement below this one has an opener but no
613
            // keyword, the opener will be incorrectly assigned to this IF statement.
614
            if (($currType === T_IF || $currType === T_ELSE)
615
                && $opener === null
616
                && $this->tokens[$i]['code'] === T_SEMICOLON
617
            ) {
618 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...
619
                    $type = $this->tokens[$stackPtr]['type'];
620
                    echo str_repeat("\t", $depth);
621
                    echo "=> Found semicolon before scope opener for $stackPtr:$type, bailing".PHP_EOL;
622
                }
623
624
                return $i;
625
            }
626
627
            // Special case for PHP control structures that have no braces.
628
            // If we find a curly brace closer before we find the opener,
629
            // we're not going to find an opener. That closer probably belongs to
630
            // a control structure higher up.
631
            if ($opener === null
632
                && $ignore === 0
633
                && $tokenType === T_CLOSE_CURLY_BRACKET
634
                && isset($this->scopeOpeners[$currType]['end'][$tokenType]) === true
635
            ) {
636 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...
637
                    $type = $this->tokens[$stackPtr]['type'];
638
                    echo str_repeat("\t", $depth);
639
                    echo "=> Found curly brace closer before scope opener for $stackPtr:$type, bailing".PHP_EOL;
640
                }
641
642
                return ($i - 1);
643
            }
644
645
            if ($opener !== null
646
                && (isset($this->tokens[$i]['scope_opener']) === false
647
                || $this->scopeOpeners[$this->tokens[$stackPtr]['code']]['shared'] === true)
648
                && isset($this->scopeOpeners[$currType]['end'][$tokenType]) === true
649
            ) {
650
                if ($ignore > 0 && $tokenType === T_CLOSE_CURLY_BRACKET) {
651
                    // The last opening bracket must have been for a string
652
                    // offset or alike, so let's ignore it.
653
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
654
                        echo str_repeat("\t", $depth);
655
                        echo '* finished ignoring curly brace *'.PHP_EOL;
656
                    }
657
658
                    $ignore--;
659
                    continue;
660
                } else if ($this->tokens[$opener]['code'] === T_OPEN_CURLY_BRACKET
661
                    && $tokenType !== T_CLOSE_CURLY_BRACKET
662
                ) {
663
                    // The opener is a curly bracket so the closer must be a curly bracket as well.
664
                    // We ignore this closer to handle cases such as T_ELSE or T_ELSEIF being considered
665
                    // a closer of T_IF when it should not.
666 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...
667
                        $type = $this->tokens[$stackPtr]['type'];
668
                        echo str_repeat("\t", $depth);
669
                        echo "=> Ignoring non-curly scope closer for $stackPtr:$type".PHP_EOL;
670
                    }
671
                } else {
672
                    $scopeCloser = $i;
673
                    $todo        = array(
674
                                    $stackPtr,
675
                                    $opener,
676
                                   );
677
678 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...
679
                        $type       = $this->tokens[$stackPtr]['type'];
680
                        $closerType = $this->tokens[$scopeCloser]['type'];
681
                        echo str_repeat("\t", $depth);
682
                        echo "=> Found scope closer ($scopeCloser:$closerType) for $stackPtr:$type".PHP_EOL;
683
                    }
684
685
                    $validCloser = true;
686
                    if (($this->tokens[$stackPtr]['code'] === T_IF || $this->tokens[$stackPtr]['code'] === T_ELSEIF)
687
                        && ($tokenType === T_ELSE || $tokenType === T_ELSEIF)
688
                    ) {
689
                        // To be a closer, this token must have an opener.
690
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
691
                            echo str_repeat("\t", $depth);
692
                            echo "* closer needs to be tested *".PHP_EOL;
693
                        }
694
695
                        $i = self::recurseScopeMap($i, ($depth + 1), $ignore);
696
697
                        if (isset($this->tokens[$scopeCloser]['scope_opener']) === false) {
698
                            $validCloser = false;
699
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
700
                                echo str_repeat("\t", $depth);
701
                                echo "* closer is not valid (no opener found) *".PHP_EOL;
702
                            }
703
                        } else if ($this->tokens[$this->tokens[$scopeCloser]['scope_opener']]['code'] !== $this->tokens[$opener]['code']) {
704
                            $validCloser = false;
705
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
706
                                echo str_repeat("\t", $depth);
707
                                $type       = $this->tokens[$this->tokens[$scopeCloser]['scope_opener']]['type'];
708
                                $openerType = $this->tokens[$opener]['type'];
709
                                echo "* closer is not valid (mismatched opener type; $type != $openerType) *".PHP_EOL;
710
                            }
711
                        } else if (PHP_CodeSniffer_VERBOSITY > 1) {
712
                            echo str_repeat("\t", $depth);
713
                            echo "* closer was valid *".PHP_EOL;
714
                        }
715
                    } else {
716
                        // The closer was not processed, so we need to
717
                        // complete that token as well.
718
                        $todo[] = $scopeCloser;
719
                    }//end if
720
721
                    if ($validCloser === true) {
722
                        foreach ($todo as $token) {
723
                            $this->tokens[$token]['scope_condition'] = $stackPtr;
724
                            $this->tokens[$token]['scope_opener']    = $opener;
725
                            $this->tokens[$token]['scope_closer']    = $scopeCloser;
726
                        }
727
728
                        if ($this->scopeOpeners[$this->tokens[$stackPtr]['code']]['shared'] === true) {
729
                            // As we are going back to where we started originally, restore
730
                            // the ignore value back to its original value.
731
                            $ignore = $originalIgnore;
732
                            return $opener;
733
                        } else if ($scopeCloser === $i
734
                            && isset($this->scopeOpeners[$tokenType]) === true
735
                        ) {
736
                            // Unset scope_condition here or else the token will appear to have
737
                            // already been processed, and it will be skipped. Normally we want that,
738
                            // but in this case, the token is both a closer and an opener, so
739
                            // it needs to act like an opener. This is also why we return the
740
                            // token before this one; so the closer has a chance to be processed
741
                            // a second time, but as an opener.
742
                            unset($this->tokens[$scopeCloser]['scope_condition']);
743
                            return ($i - 1);
744
                        } else {
745
                            return $i;
746
                        }
747
                    } else {
748
                        continue;
749
                    }//end if
750
                }//end if
751
            }//end if
752
753
            // Is this an opening condition ?
754
            if (isset($this->scopeOpeners[$tokenType]) === true) {
755
                if ($opener === null) {
756
                    if ($tokenType === T_USE) {
757
                        // PHP use keywords are special because they can be
758
                        // used as blocks but also inline in function definitions.
759
                        // So if we find them nested inside another opener, just skip them.
760
                        continue;
761
                    }
762
763
                    if ($tokenType === T_FUNCTION
764
                        && $this->tokens[$stackPtr]['code'] !== T_FUNCTION
765
                    ) {
766
                        // Probably a closure, so process it manually.
767 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...
768
                            $type = $this->tokens[$stackPtr]['type'];
769
                            echo str_repeat("\t", $depth);
770
                            echo "=> Found function before scope opener for $stackPtr:$type, processing manually".PHP_EOL;
771
                        }
772
773 View Code Duplication
                        if (isset($this->tokens[$i]['scope_closer']) === true) {
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...
774
                            // We've already processed this closure.
775
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
776
                                echo str_repeat("\t", $depth);
777
                                echo '* already processed, skipping *'.PHP_EOL;
778
                            }
779
780
                            $i = $this->tokens[$i]['scope_closer'];
781
                            continue;
782
                        }
783
784
                        $i = self::recurseScopeMap($i, ($depth + 1), $ignore);
785
                        continue;
786
                    }//end if
787
788
                    // Found another opening condition but still haven't
789
                    // found our opener, so we are never going to find one.
790 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...
791
                        $type = $this->tokens[$stackPtr]['type'];
792
                        echo str_repeat("\t", $depth);
793
                        echo "=> Found new opening condition before scope opener for $stackPtr:$type, ";
794
                    }
795
796
                    if (($this->tokens[$stackPtr]['code'] === T_IF
797
                        || $this->tokens[$stackPtr]['code'] === T_ELSEIF
798
                        || $this->tokens[$stackPtr]['code'] === T_ELSE)
799
                        && ($this->tokens[$i]['code'] === T_ELSE
800
                        || $this->tokens[$i]['code'] === T_ELSEIF)
801
                    ) {
802
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
803
                            echo "continuing".PHP_EOL;
804
                        }
805
806
                        return ($i - 1);
807
                    } else {
808
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
809
                            echo "backtracking".PHP_EOL;
810
                        }
811
812
                        return $stackPtr;
813
                    }
814
                }//end if
815
816
                if (PHP_CodeSniffer_VERBOSITY > 1) {
817
                    echo str_repeat("\t", $depth);
818
                    echo '* token is an opening condition *'.PHP_EOL;
819
                }
820
821
                $isShared = ($this->scopeOpeners[$tokenType]['shared'] === true);
822
823
                if (isset($this->tokens[$i]['scope_condition']) === true) {
824
                    // We've been here before.
825
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
826
                        echo str_repeat("\t", $depth);
827
                        echo '* already processed, skipping *'.PHP_EOL;
828
                    }
829
830 View Code Duplication
                    if ($isShared === false
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...
831
                        && isset($this->tokens[$i]['scope_closer']) === true
832
                    ) {
833
                        $i = $this->tokens[$i]['scope_closer'];
834
                    }
835
836
                    continue;
837
                } else if ($currType === $tokenType
838
                    && $isShared === false
839
                    && $opener === null
840
                ) {
841
                    // We haven't yet found our opener, but we have found another
842
                    // scope opener which is the same type as us, and we don't
843
                    // share openers, so we will never find one.
844
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
845
                        echo str_repeat("\t", $depth);
846
                        echo '* it was another token\'s opener, bailing *'.PHP_EOL;
847
                    }
848
849
                    return $stackPtr;
850
                } else {
851
                    if (PHP_CodeSniffer_VERBOSITY > 1) {
852
                        echo str_repeat("\t", $depth);
853
                        echo '* searching for opener *'.PHP_EOL;
854
                    }
855
856 View Code Duplication
                    if (isset($this->scopeOpeners[$tokenType]['end'][T_CLOSE_CURLY_BRACKET]) === true) {
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...
857
                        $oldIgnore = $ignore;
858
                        $ignore    = 0;
859
                    }
860
861
                    // PHP has a max nesting level for functions. Stop before we hit that limit
862
                    // because too many loops means we've run into trouble anyway.
863 View Code Duplication
                    if ($depth > 50) {
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...
864
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
865
                            echo str_repeat("\t", $depth);
866
                            echo '* reached maximum nesting level; aborting *'.PHP_EOL;
867
                        }
868
869
                        throw new RuntimeException('Maximum nesting level reached; file could not be processed');
870
                    }
871
872
                    $oldDepth = $depth;
873
                    if ($isShared === true
874
                        && isset($this->scopeOpeners[$tokenType]['with'][$currType]) === true
875
                    ) {
876
                        // Don't allow the depth to increment because this is
877
                        // possibly not a true nesting if we are sharing our closer.
878
                        // This can happen, for example, when a SWITCH has a large
879
                        // number of CASE statements with the same shared BREAK.
880
                        $depth--;
881
                    }
882
883
                    $i     = self::recurseScopeMap($i, ($depth + 1), $ignore);
884
                    $depth = $oldDepth;
885
886 View Code Duplication
                    if (isset($this->scopeOpeners[$tokenType]['end'][T_CLOSE_CURLY_BRACKET]) === true) {
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...
887
                        $ignore = $oldIgnore;
0 ignored issues
show
Bug introduced by
The variable $oldIgnore 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...
888
                    }
889
                }//end if
890
            }//end if
891
892
            if (isset($this->scopeOpeners[$currType]['start'][$tokenType]) === true
893
                && $opener === null
894
            ) {
895
                if ($tokenType === T_OPEN_CURLY_BRACKET) {
896
                    if (isset($this->tokens[$stackPtr]['parenthesis_closer']) === true
897
                        && $i < $this->tokens[$stackPtr]['parenthesis_closer']
898
                    ) {
899
                        // We found a curly brace inside the condition of the
900
                        // current scope opener, so it must be a string offset.
901
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
902
                            echo str_repeat("\t", $depth);
903
                            echo '* ignoring curly brace *'.PHP_EOL;
904
                        }
905
906
                        $ignore++;
907
                    } else {
908
                        // Make sure this is actually an opener and not a
909
                        // string offset (e.g., $var{0}).
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
910
                        for ($x = ($i - 1); $x > 0; $x--) {
911
                            if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) {
912
                                continue;
913 View Code Duplication
                            } else {
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...
914
                                // If the first non-whitespace/comment token is a
915
                                // variable or object operator then this is an opener
916
                                // for a string offset and not a scope.
917
                                if ($this->tokens[$x]['code'] === T_VARIABLE
918
                                    || $this->tokens[$x]['code'] === T_OBJECT_OPERATOR
919
                                ) {
920
                                    if (PHP_CodeSniffer_VERBOSITY > 1) {
921
                                        echo str_repeat("\t", $depth);
922
                                        echo '* ignoring curly brace *'.PHP_EOL;
923
                                    }
924
925
                                    $ignore++;
926
                                }//end if
927
928
                                break;
929
                            }//end if
930
                        }//end for
931
                    }//end if
932
                }//end if
933
934
                if ($ignore === 0 || $tokenType !== T_OPEN_CURLY_BRACKET) {
935
                    // We found the opening scope token for $currType.
936 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...
937
                        $type = $this->tokens[$stackPtr]['type'];
938
                        echo str_repeat("\t", $depth);
939
                        echo "=> Found scope opener for $stackPtr:$type".PHP_EOL;
940
                    }
941
942
                    $opener = $i;
943
                }
944
            } else if ($tokenType === T_OPEN_PARENTHESIS) {
945
                if (isset($this->tokens[$i]['parenthesis_owner']) === true) {
946
                    $owner = $this->tokens[$i]['parenthesis_owner'];
947 View Code Duplication
                    if (isset(Util\Tokens::$scopeOpeners[$this->tokens[$owner]['code']]) === true
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...
948
                        && isset($this->tokens[$i]['parenthesis_closer']) === true
949
                    ) {
950
                        // If we get into here, then we opened a parenthesis for
951
                        // a scope (eg. an if or else if) so we need to update the
952
                        // start of the line so that when we check to see
953
                        // if the closing parenthesis is more than 3 lines away from
954
                        // the statement, we check from the closing parenthesis.
955
                        $startLine = $this->tokens[$this->tokens[$i]['parenthesis_closer']]['line'];
956
                    }
957
                }
958
            } else if ($tokenType === T_OPEN_CURLY_BRACKET && $opener !== null) {
959
                // We opened something that we don't have a scope opener for.
960
                // Examples of this are curly brackets for string offsets etc.
961
                // We want to ignore this so that we don't have an invalid scope
962
                // map.
963
                if (PHP_CodeSniffer_VERBOSITY > 1) {
964
                    echo str_repeat("\t", $depth);
965
                    echo '* ignoring curly brace *'.PHP_EOL;
966
                }
967
968
                $ignore++;
969
            } else if ($tokenType === T_CLOSE_CURLY_BRACKET && $ignore > 0) {
970
                // We found the end token for the opener we were ignoring.
971
                if (PHP_CodeSniffer_VERBOSITY > 1) {
972
                    echo str_repeat("\t", $depth);
973
                    echo '* finished ignoring curly brace *'.PHP_EOL;
974
                }
975
976
                $ignore--;
977
            } else if ($opener === null
978
                && isset($this->scopeOpeners[$currType]) === true
979
            ) {
980
                // If we still haven't found the opener after 3 lines,
981
                // we're not going to find it, unless we know it requires
982
                // an opener (in which case we better keep looking) or the last
983
                // token was empty (in which case we'll just confirm there is
984
                // more code in this file and not just a big comment).
985
                if ($this->tokens[$i]['line'] >= ($startLine + 3)
986
                    && isset(Util\Tokens::$emptyTokens[$this->tokens[($i - 1)]['code']]) === false
987
                ) {
988
                    if ($this->scopeOpeners[$currType]['strict'] === true) {
989 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...
990
                            $type  = $this->tokens[$stackPtr]['type'];
991
                            $lines = ($this->tokens[$i]['line'] - $startLine);
992
                            echo str_repeat("\t", $depth);
993
                            echo "=> Still looking for $stackPtr:$type scope opener after $lines lines".PHP_EOL;
994
                        }
995 View Code Duplication
                    } else {
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...
996
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
997
                            $type = $this->tokens[$stackPtr]['type'];
998
                            echo str_repeat("\t", $depth);
999
                            echo "=> Couldn't find scope opener for $stackPtr:$type, bailing".PHP_EOL;
1000
                        }
1001
1002
                        return $stackPtr;
1003
                    }
1004
                }
1005
            } else if ($opener !== null
1006
                && $tokenType !== T_BREAK
1007
                && isset($this->endScopeTokens[$tokenType]) === true
0 ignored issues
show
Bug introduced by
The property endScopeTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1008
            ) {
1009
                if (isset($this->tokens[$i]['scope_condition']) === false) {
1010
                    if ($ignore > 0) {
1011
                        // We found the end token for the opener we were ignoring.
1012
                        if (PHP_CodeSniffer_VERBOSITY > 1) {
1013
                            echo str_repeat("\t", $depth);
1014
                            echo '* finished ignoring curly brace *'.PHP_EOL;
1015
                        }
1016
1017
                        $ignore--;
1018
                    } else {
1019
                        // We found a token that closes the scope but it doesn't
1020
                        // have a condition, so it belongs to another token and
1021
                        // our token doesn't have a closer, so pretend this is
1022
                        // the closer.
1023 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...
1024
                            $type = $this->tokens[$stackPtr]['type'];
1025
                            echo str_repeat("\t", $depth);
1026
                            echo "=> Found (unexpected) scope closer for $stackPtr:$type".PHP_EOL;
1027
                        }
1028
1029 View Code Duplication
                        foreach (array($stackPtr, $opener) as $token) {
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...
1030
                            $this->tokens[$token]['scope_condition'] = $stackPtr;
1031
                            $this->tokens[$token]['scope_opener']    = $opener;
1032
                            $this->tokens[$token]['scope_closer']    = $i;
1033
                        }
1034
1035
                        return ($i - 1);
1036
                    }//end if
1037
                }//end if
1038
            }//end if
1039
        }//end for
1040
1041
        return $stackPtr;
1042
1043
    }//end recurseScopeMap()
1044
1045
1046
    /**
1047
     * Constructs the level map.
1048
     *
1049
     * The level map adds a 'level' index to each token which indicates the
1050
     * depth that a token within a set of scope blocks. It also adds a
1051
     * 'condition' index which is an array of the scope conditions that opened
1052
     * each of the scopes - position 0 being the first scope opener.
1053
     *
1054
     * @return void
1055
     */
1056
    private function createLevelMap()
1057
    {
1058
        if (PHP_CodeSniffer_VERBOSITY > 1) {
1059
            echo "\t*** START LEVEL MAP ***".PHP_EOL;
1060
        }
1061
1062
        $this->numTokens = count($this->tokens);
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1063
        $level           = 0;
1064
        $conditions      = array();
1065
        $lastOpener      = null;
1066
        $openers         = array();
1067
1068
        for ($i = 0; $i < $this->numTokens; $i++) {
0 ignored issues
show
Bug introduced by
The property numTokens does not seem to exist. Did you mean tokens?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1069
            if (PHP_CodeSniffer_VERBOSITY > 1) {
1070
                $type = $this->tokens[$i]['type'];
1071
                $line = $this->tokens[$i]['line'];
1072
                $len  = $this->tokens[$i]['length'];
1073
                $col  = $this->tokens[$i]['column'];
1074
1075
                $content = Util\Common::prepareForOutput($this->tokens[$i]['content']);
1076
1077
                echo str_repeat("\t", ($level + 1));
1078
                echo "Process token $i on line $line [col:$col;len:$len;lvl:$level;";
1079
                if (empty($conditions) !== true) {
1080
                    $condString = 'conds;';
1081
                    foreach ($conditions as $condition) {
1082
                        $condString .= token_name($condition).',';
1083
                    }
1084
1085
                    echo rtrim($condString, ',').';';
1086
                }
1087
1088
                echo "]: $type => $content".PHP_EOL;
1089
            }//end if
1090
1091
            $this->tokens[$i]['level']      = $level;
1092
            $this->tokens[$i]['conditions'] = $conditions;
1093
1094
            if (isset($this->tokens[$i]['scope_condition']) === true) {
1095
                // Check to see if this token opened the scope.
1096
                if ($this->tokens[$i]['scope_opener'] === $i) {
1097
                    $stackPtr = $this->tokens[$i]['scope_condition'];
1098 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...
1099
                        $type = $this->tokens[$stackPtr]['type'];
1100
                        echo str_repeat("\t", ($level + 1));
1101
                        echo "=> Found scope opener for $stackPtr:$type".PHP_EOL;
1102
                    }
1103
1104
                    $stackPtr = $this->tokens[$i]['scope_condition'];
1105
1106
                    // If we find a scope opener that has a shared closer,
1107
                    // then we need to go back over the condition map that we
1108
                    // just created and fix ourselves as we just added some
1109
                    // conditions where there was none. This happens for T_CASE
1110
                    // statements that are using the same break statement.
1111
                    if ($lastOpener !== null && $this->tokens[$lastOpener]['scope_closer'] === $this->tokens[$i]['scope_closer']) {
1112
                        // This opener shares its closer with the previous opener,
1113
                        // but we still need to check if the two openers share their
1114
                        // closer with each other directly (like CASE and DEFAULT)
1115
                        // or if they are just sharing because one doesn't have a
1116
                        // closer (like CASE with no BREAK using a SWITCHes closer).
1117
                        $thisType = $this->tokens[$this->tokens[$i]['scope_condition']]['code'];
1118
                        $opener   = $this->tokens[$lastOpener]['scope_condition'];
1119
1120
                        $isShared = isset($this->scopeOpeners[$thisType]['with'][$this->tokens[$opener]['code']]);
1121
1122
                        reset($this->scopeOpeners[$thisType]['end']);
1123
                        reset($this->scopeOpeners[$this->tokens[$opener]['code']]['end']);
1124
                        $sameEnd = (current($this->scopeOpeners[$thisType]['end']) === current($this->scopeOpeners[$this->tokens[$opener]['code']]['end']));
1125
1126
                        if ($isShared === true && $sameEnd === true) {
1127
                            $badToken = $opener;
1128
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
1129
                                $type = $this->tokens[$badToken]['type'];
1130
                                echo str_repeat("\t", ($level + 1));
1131
                                echo "* shared closer, cleaning up $badToken:$type *".PHP_EOL;
1132
                            }
1133
1134 View Code Duplication
                            for ($x = $this->tokens[$i]['scope_condition']; $x <= $i; $x++) {
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...
1135
                                $oldConditions = $this->tokens[$x]['conditions'];
1136
                                $oldLevel      = $this->tokens[$x]['level'];
1137
                                $this->tokens[$x]['level']--;
1138
                                unset($this->tokens[$x]['conditions'][$badToken]);
1139
                                if (PHP_CodeSniffer_VERBOSITY > 1) {
1140
                                    $type     = $this->tokens[$x]['type'];
1141
                                    $oldConds = '';
1142
                                    foreach ($oldConditions as $condition) {
1143
                                        $oldConds .= token_name($condition).',';
1144
                                    }
1145
1146
                                    $oldConds = rtrim($oldConds, ',');
1147
1148
                                    $newConds = '';
1149
                                    foreach ($this->tokens[$x]['conditions'] as $condition) {
1150
                                        $newConds .= token_name($condition).',';
1151
                                    }
1152
1153
                                    $newConds = rtrim($newConds, ',');
1154
1155
                                    $newLevel = $this->tokens[$x]['level'];
1156
                                    echo str_repeat("\t", ($level + 1));
1157
                                    echo "* cleaned $x:$type *".PHP_EOL;
1158
                                    echo str_repeat("\t", ($level + 2));
1159
                                    echo "=> level changed from $oldLevel to $newLevel".PHP_EOL;
1160
                                    echo str_repeat("\t", ($level + 2));
1161
                                    echo "=> conditions changed from $oldConds to $newConds".PHP_EOL;
1162
                                }//end if
1163
                            }//end for
1164
1165
                            unset($conditions[$badToken]);
1166
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
1167
                                $type = $this->tokens[$badToken]['type'];
1168
                                echo str_repeat("\t", ($level + 1));
1169
                                echo "* token $badToken:$type removed from conditions array *".PHP_EOL;
1170
                            }
1171
1172
                            unset($openers[$lastOpener]);
1173
1174
                            $level--;
1175 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...
1176
                                echo str_repeat("\t", ($level + 2));
1177
                                echo '* level decreased *'.PHP_EOL;
1178
                            }
1179
                        }//end if
1180
                    }//end if
1181
1182
                    $level++;
1183 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...
1184
                        echo str_repeat("\t", ($level + 1));
1185
                        echo '* level increased *'.PHP_EOL;
1186
                    }
1187
1188
                    $conditions[$stackPtr] = $this->tokens[$stackPtr]['code'];
1189 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...
1190
                        $type = $this->tokens[$stackPtr]['type'];
1191
                        echo str_repeat("\t", ($level + 1));
1192
                        echo "* token $stackPtr:$type added to conditions array *".PHP_EOL;
1193
                    }
1194
1195
                    $lastOpener = $this->tokens[$i]['scope_opener'];
1196
                    if ($lastOpener !== null) {
1197
                        $openers[$lastOpener] = $lastOpener;
1198
                    }
1199
                } else if ($lastOpener !== null && $this->tokens[$lastOpener]['scope_closer'] === $i) {
1200
                    foreach (array_reverse($openers) as $opener) {
1201
                        if ($this->tokens[$opener]['scope_closer'] === $i) {
1202
                            $oldOpener = array_pop($openers);
1203
                            if (empty($openers) === false) {
1204
                                $lastOpener           = array_pop($openers);
1205
                                $openers[$lastOpener] = $lastOpener;
1206
                            } else {
1207
                                $lastOpener = null;
1208
                            }
1209
1210
                            if (PHP_CodeSniffer_VERBOSITY > 1) {
1211
                                $type = $this->tokens[$oldOpener]['type'];
1212
                                echo str_repeat("\t", ($level + 1));
1213
                                echo "=> Found scope closer for $oldOpener:$type".PHP_EOL;
1214
                            }
1215
1216
                            $oldCondition = array_pop($conditions);
1217 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...
1218
                                echo str_repeat("\t", ($level + 1));
1219
                                echo '* token '.token_name($oldCondition).' removed from conditions array *'.PHP_EOL;
1220
                            }
1221
1222
                            // Make sure this closer actually belongs to us.
1223
                            // Either the condition also has to think this is the
1224
                            // closer, or it has to allow sharing with us.
1225
                            $condition = $this->tokens[$this->tokens[$i]['scope_condition']]['code'];
1226
                            if ($condition !== $oldCondition) {
1227
                                if (isset($this->scopeOpeners[$oldCondition]['with'][$condition]) === false) {
1228
                                    $badToken = $this->tokens[$oldOpener]['scope_condition'];
1229
1230
                                    if (PHP_CodeSniffer_VERBOSITY > 1) {
1231
                                        $type = token_name($oldCondition);
1232
                                        echo str_repeat("\t", ($level + 1));
1233
                                        echo "* scope closer was bad, cleaning up $badToken:$type *".PHP_EOL;
1234
                                    }
1235
1236 View Code Duplication
                                    for ($x = ($oldOpener + 1); $x <= $i; $x++) {
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...
1237
                                        $oldConditions = $this->tokens[$x]['conditions'];
1238
                                        $oldLevel      = $this->tokens[$x]['level'];
1239
                                        $this->tokens[$x]['level']--;
1240
                                        unset($this->tokens[$x]['conditions'][$badToken]);
1241
                                        if (PHP_CodeSniffer_VERBOSITY > 1) {
1242
                                            $type     = $this->tokens[$x]['type'];
1243
                                            $oldConds = '';
1244
                                            foreach ($oldConditions as $condition) {
1245
                                                $oldConds .= token_name($condition).',';
1246
                                            }
1247
1248
                                            $oldConds = rtrim($oldConds, ',');
1249
1250
                                            $newConds = '';
1251
                                            foreach ($this->tokens[$x]['conditions'] as $condition) {
1252
                                                $newConds .= token_name($condition).',';
1253
                                            }
1254
1255
                                            $newConds = rtrim($newConds, ',');
1256
1257
                                            $newLevel = $this->tokens[$x]['level'];
1258
                                            echo str_repeat("\t", ($level + 1));
1259
                                            echo "* cleaned $x:$type *".PHP_EOL;
1260
                                            echo str_repeat("\t", ($level + 2));
1261
                                            echo "=> level changed from $oldLevel to $newLevel".PHP_EOL;
1262
                                            echo str_repeat("\t", ($level + 2));
1263
                                            echo "=> conditions changed from $oldConds to $newConds".PHP_EOL;
1264
                                        }//end if
1265
                                    }//end for
1266
                                }//end if
1267
                            }//end if
1268
1269
                            $level--;
1270 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...
1271
                                echo str_repeat("\t", ($level + 2));
1272
                                echo '* level decreased *'.PHP_EOL;
1273
                            }
1274
1275
                            $this->tokens[$i]['level']      = $level;
1276
                            $this->tokens[$i]['conditions'] = $conditions;
1277
                        }//end if
1278
                    }//end foreach
1279
                }//end if
1280
            }//end if
1281
        }//end for
1282
1283
        if (PHP_CodeSniffer_VERBOSITY > 1) {
1284
            echo "\t*** END LEVEL MAP ***".PHP_EOL;
1285
        }
1286
1287
    }//end createLevelMap()
1288
1289
1290
}//end class
1291