Completed
Pull Request — master (#457)
by Claus
01:57
created

Debugger::debugSequence()   F

Complexity

Conditions 11
Paths 396

Size

Total Lines 77

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 396
nop 1
dl 0
loc 77
rs 3.7284
c 0
b 0
f 0

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
declare(strict_types=1);
3
4
namespace TYPO3Fluid\Fluid\Core\NewParser;
5
6
use TYPO3Fluid\Fluid\Core\Parser\Context;
7
8
class Debugger
9
{
10
    private $fp;
11
12
    public function __construct(string $logFile)
13
    {
14
        $this->fp = fopen($logFile, 'w+');
15
    }
16
17
    public function __destruct()
18
    {
19
        fwrite($this->fp, PHP_EOL . PHP_EOL);
20
        fclose($this->fp);
21
    }
22
23
    public function writeLogContent(string $content): void
24
    {
25
        fwrite($this->fp, $content);
26
    }
27
28
    public function writeLogLine(string $line, int $color = 0): void
29
    {
30
        $this->writeLogContent(($color === 0 ? $line : "\033[01;" . (string) $color . 'm' . $line . "\033[01;0m") . PHP_EOL);
31
    }
32
33
    public function debugSequence(\Iterator $sequence): void
34
    {
35
        $colors = [
36
            "\033[01;0m",
37
            "\033[01;31m",
38
            "\033[01;32m",
39
            "\033[01;34m",
40
            "\033[01;35m",
41
            "\033[01;36m",
42
        ];
43
44
        $reflect = new \ReflectionClass(Context::class);
45
        $constants = array_flip($reflect->getConstants());
46
        $legend = '';
47
        foreach ($constants as $index => $constant) {
48
            $legend .= $colors[$index] ?? "\033[01;0m";
49
            $legend .= substr($constant, 8);
50
            $legend .= "\033[0m";
51
            $legend .= ' ';
52
        }
53
54
        $captures = [];
55
        $symbols = [];
56
        $contexts = [];
57
        $nesting = [];
58
59
        $spacing = '';
60
61
        try {
62
            foreach ($sequence as $symbol => $capture) {
63
                $captures[] = $capture->captured === null ? null : str_replace(PHP_EOL, '', $capture->captured);
64
                $symbols[] = $symbol;
65
                $contexts[] = $sequencer->position->context->context;
0 ignored issues
show
Bug introduced by
The variable $sequencer does not exist. Did you mean $sequence?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
66
                $nesting[] = count($sequencer->position->stack);
0 ignored issues
show
Bug introduced by
The variable $sequencer does not exist. Did you mean $sequence?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
67
            }
68
        } catch (\RuntimeException $exception) {
69
            $this->writeLogLine($exception->getMessage(), 31);
70
        }
71
72
73
        $this->writeLogLine(PHP_EOL);
74
        $this->writeLogLine($legend);
75
        $this->writeLogLine(str_repeat('—', strlen(str_replace(PHP_EOL, '', $sequencer->source->source))));
0 ignored issues
show
Bug introduced by
The variable $sequencer does not exist. Did you mean $sequence?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
76
77
        $symbolLine = '';
78
        foreach ($symbols as $index => $symbol) {
79
            $char = $symbol === Splitter::BYTE_BACKSLASH ? '\\' : chr($symbol);
80
            $capturedLength = strlen((string)$captures[$index]) + 1;
81
            $symbolLine .= $colors[$contexts[$index]] ?? "\033[01;0m";
82
            $symbolLine .= str_repeat(' ', max($capturedLength - 1, 0)) . $char . $spacing;
83
            #echo str_repeat((string)$contexts[$index], $capturedLength > 0 ? $capturedLength : 1);
84
            $symbolLine .= "\033[0m";
85
        }
86
87
        $this->writeLogLine($symbolLine, 0);
88
89
        $captureLine = '';
90
        foreach ($captures as $index => $capture) {
91
            $char = $symbol === Splitter::BYTE_BACKSLASH ? '\\' : chr($symbol);
0 ignored issues
show
Bug introduced by
The variable $symbol 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...
92
            $captureLine .= $colors[$contexts[$index]] ?? "\033[01;0m";
93
            $captureLine .= $capture;
94
            //$captureLine .= str_pad(addslashes(chr($symbols[$index])), 1, ' ') . '   ';
95
            $captureLine .= str_repeat(' ', strlen($char)) . $spacing;
96
            $captureLine .= "\033[0m";
97
        }
98
99
        $this->writeLogLine($captureLine);
100
101
        $nestingLine = '';
102
        foreach ($nesting as $index => $depth) {
103
            $capturedLength = strlen(str_replace(PHP_EOL, '', (string)$captures[$index])) + 1;
104
            $nestingLine .= str_repeat((string)$depth, ($capturedLength > 0 ? $capturedLength : 0)) . $spacing;
105
        }
106
107
        $this->writeLogLine($nestingLine);
108
        $this->writeLogLine(str_repeat('—', strlen(str_replace(PHP_EOL, '', $sequencer->source->source))));
0 ignored issues
show
Bug introduced by
The variable $sequencer does not exist. Did you mean $sequence?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
109
    }
110
}