Completed
Pull Request — master (#201)
by
unknown
02:09 queued 43s
created

JsFunctionsScanner::getFunctions()   F

Complexity

Conditions 48
Paths 253

Size

Total Lines 173

Duplication

Lines 32
Ratio 18.5 %

Importance

Changes 0
Metric Value
cc 48
nc 253
nop 1
dl 32
loc 173
rs 2.1366
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
3
namespace Gettext\Utils;
4
5
class JsFunctionsScanner extends FunctionsScanner
6
{
7
    protected $code;
8
    protected $status = [];
9
10
    /**
11
     * Constructor.
12
     *
13
     * @param string $code The php code to scan
14
     */
15
    public function __construct($code)
16
    {
17
        // Normalize newline characters
18
        $this->code = str_replace(["\r\n", "\n\r", "\r"], "\n", $code);
19
    }
20
21
    /**
22
     * {@inheritdoc}
23
     */
24
    public function getFunctions(array $constants = [])
25
    {
26
        $length = strlen($this->code);
27
        $line = 1;
28
        $buffer = '';
29
        $functions = [];
30
        $bufferFunctions = [];
31
        $char = null;
32
33
        for ($pos = 0; $pos < $length; ++$pos) {
34
            $prev = $char;
35
            $char = $this->code[$pos];
36
            $next = isset($this->code[$pos + 1]) ? $this->code[$pos + 1] : null;
37
38
            switch ($char) {
39
                case '\\':
40
                    switch ($this->status()) {
41
                        case 'simple-quote':
42
                            break 2;
43
                        case 'double-quote':
44
                            break 2;
45
46
                        default:
47
48
                            $prev = $char;
0 ignored issues
show
Unused Code introduced by
$prev 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...
49
                            $char = $next;
50
                            $pos++;
51
                            $next = isset($this->code[$pos]) ? $this->code[$pos] : null;
0 ignored issues
show
Unused Code introduced by
$next 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...
52
53
                            break;
54
                    }
55
56
                case "\n":
57
                    ++$line;
58
59
                    if ($this->status('line-comment')) {
60
                        $this->upStatus();
61
                    }
62
                    break;
63
64
                case '/':
65
                    switch ($this->status()) {
66
                        case 'simple-quote':
67
                        case 'double-quote':
68
                        case 'line-comment':
69
                            break;
70
71
                        case 'block-comment':
72
                            if ($prev === '*') {
73
                                $this->upStatus();
74
                            }
75
                            break;
76
77
                        default:
78
                            if ($next === '/') {
79
                                $this->downStatus('line-comment');
80
                            } elseif ($next === '*') {
81
                                $this->downStatus('block-comment');
82
                            }
83
                            break;
84
                    }
85
                    break;
86
87 View Code Duplication
                case "'":
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...
88
                    switch ($this->status()) {
89
                        case 'simple-quote':
90
                            $this->upStatus();
91
                            break;
92
93
                        case 'line-comment':
94
                        case 'block-comment':
95
                        case 'double-quote':
96
                            break;
97
98
                        default:
99
                            $this->downStatus('simple-quote');
100
                            break;
101
                    }
102
                    break;
103
104 View Code Duplication
                case '"':
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...
105
                    switch ($this->status()) {
106
                        case 'double-quote':
107
                            $this->upStatus();
108
                            break;
109
110
                        case 'line-comment':
111
                        case 'block-comment':
112
                        case 'simple-quote':
113
                            break;
114
115
                        default:
116
                            $this->downStatus('double-quote');
117
                            break;
118
                    }
119
                    break;
120
121
                case '(':
122
                    switch ($this->status()) {
123
                        case 'simple-quote':
124
                        case 'double-quote':
125
                        case 'line-comment':
126
                        case 'block-comment':
127
                        case 'line-comment':
128
                            break;
129
130
                        default:
131
                            if ($buffer && preg_match('/(\w+)$/', $buffer, $matches)) {
132
                                $this->downStatus('function');
133
                                array_unshift($bufferFunctions, [$matches[1], $line, []]);
134
                                $buffer = '';
135
                                continue 3;
136
                            }
137
                            break;
138
                    }
139
                    break;
140
141
                case ')':
142
                    switch ($this->status()) {
143
                        case 'function':
144
                            if (($argument = self::prepareArgument($buffer))) {
145
                                $bufferFunctions[0][2][] = $argument;
146
                            }
147
148
                            if (!empty($bufferFunctions)) {
149
                                $functions[] = array_shift($bufferFunctions);
150
                            }
151
152
                            $this->upStatus();
153
                            $buffer = '';
154
                            continue 3;
155
                    }
156
                    break;
157
158
                case ',':
159
                    switch ($this->status()) {
160
                        case 'function':
161
                            if (($argument = self::prepareArgument($buffer))) {
162
                                $bufferFunctions[0][2][] = $argument;
163
                            }
164
165
                            $buffer = '';
166
                            continue 3;
167
                    }
168
                    break;
169
170
                case ' ':
171
                case '\t':
172
                    switch ($this->status()) {
173
                        case 'double-quote':
174
                        case 'simple-quote':
175
                            break;
176
177
                        default:
178
                            $buffer = '';
179
                            continue 3;
180
                    }
181
                    break;
182
            }
183
184
            switch ($this->status()) {
185
                case 'line-comment':
186
                case 'block-comment':
187
                    break;
188
189
                default:
190
                    $buffer .= $char;
191
                    break;
192
            }
193
        }
194
195
        return $functions;
196
    }
197
198
    /**
199
     * Get the current context of the scan.
200
     *
201
     * @param null|string $match To check whether the current status is this value
202
     *
203
     * @return string|bool
204
     */
205
    protected function status($match = null)
206
    {
207
        $status = isset($this->status[0]) ? $this->status[0] : null;
208
209
        if ($match !== null) {
210
            return $status === $match;
211
        }
212
213
        return $status;
214
    }
215
216
    /**
217
     * Add a new status to the stack.
218
     *
219
     * @param string $status
220
     */
221
    protected function downStatus($status)
222
    {
223
        array_unshift($this->status, $status);
224
    }
225
226
    /**
227
     * Removes and return the current status.
228
     *
229
     * @return string|null
230
     */
231
    protected function upStatus()
232
    {
233
        return array_shift($this->status);
234
    }
235
236
    /**
237
     * Prepares the arguments found in functions.
238
     *
239
     * @param string $argument
240
     *
241
     * @return string
242
     */
243
    protected static function prepareArgument($argument)
244
    {
245
        $argument = isset($argument) ? $argument : '';
246
247
        if (!$argument) {
248
            return null;
249
        }
250
251
        if ($argument[0] === '"' || $argument[0] === "'") {
252
            $argument = substr($argument, 1, -1);
253
        }
254
255
        $replace = [
256
            '\n' => "\n",
257
            '\t' => "\t",
258
        ];
259
260
        return str_replace(array_keys($replace), array_values($replace), $argument);
261
    }
262
}
263