Completed
Push — master ( 2042ea...18e329 )
by Oscar
02:29
created

JsFunctionsScanner   B

Complexity

Total Complexity 54

Size/Duplication

Total Lines 228
Duplicated Lines 14.04 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 5
Bugs 3 Features 0
Metric Value
c 5
b 3
f 0
dl 32
loc 228
rs 7.0642
wmc 54
lcom 1
cbo 1

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
F getFunctions() 32 151 43
A status() 0 10 3
A downStatus() 0 4 1
A upStatus() 0 4 1
B prepareArgument() 0 12 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

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

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

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

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

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
        $this->code = $code;
18
    }
19
20
    /**
21
     * {@inheritdoc}
22
     */
23
    public function getFunctions()
24
    {
25
        $length = strlen($this->code);
26
        $line = 1;
27
        $buffer = '';
28
        $functions = [];
29
        $bufferFunctions = [];
30
        $char = null;
31
32
        for ($pos = 0; $pos < $length; ++$pos) {
33
            $prev = $char;
34
            $char = $this->code[$pos];
35
            $next = isset($this->code[$pos]) ? $this->code[$pos] : null;
36
37
            switch ($char) {
38
                case "\n":
39
                    ++$line;
40
41
                    if ($this->status('line-comment')) {
42
                        $this->upStatus();
43
                    }
44
                    break;
45
46
                case '/':
47
                    switch ($this->status()) {
48
                        case 'simple-quote':
49
                        case 'double-quote':
50
                        case 'line-comment':
51
                            break;
52
53
                        case 'block-comment':
54
                            if ($prev === '*') {
55
                                $this->upStatus();
56
                            }
57
                            break;
58
59
                        default:
60
                            if ($next === '/') {
61
                                $this->downStatus('line-comment');
62
                            } elseif ($next === '*') {
63
                                $this->downStatus('block-comment');
64
                            }
65
                            break;
66
                    }
67
                    break;
68
69 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...
70
                    switch ($this->status()) {
71
                        case 'simple-quote':
72
                            $this->upStatus();
73
                            break;
74
75
                        case 'line-comment':
76
                        case 'block-comment':
77
                        case 'double-quote':
78
                            break;
79
80
                        default:
81
                            $this->downStatus('simple-quote');
82
                            break;
83
                    }
84
                    break;
85
86 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...
87
                    switch ($this->status()) {
88
                        case 'double-quote':
89
                            $this->upStatus();
90
                            break;
91
92
                        case 'line-comment':
93
                        case 'block-comment':
94
                        case 'simple-quote':
95
                            break;
96
97
                        default:
98
                            $this->downStatus('double-quote');
99
                            break;
100
                    }
101
                    break;
102
103
                case '(':
104
                    switch ($this->status()) {
105
                        case 'double-quote':
106
                        case 'line-comment':
107
                        case 'block-comment':
108
                        case 'line-comment':
109
                            break;
110
111
                        default:
112
                            if ($buffer && preg_match('/(\w+)$/', $buffer, $matches)) {
113
                                $this->downStatus('function');
114
                                array_unshift($bufferFunctions, [$matches[1], $line, []]);
115
                                $buffer = '';
116
                                continue 3;
117
                            }
118
                            break;
119
                    }
120
                    break;
121
122
                case ')':
123
                    switch ($this->status()) {
124
                        case 'function':
125
                            if (($argument = self::prepareArgument($buffer))) {
126
                                $bufferFunctions[0][2][] = $argument;
127
                            }
128
129
                            if (!empty($bufferFunctions)) {
130
                                $functions[] = array_shift($bufferFunctions);
131
                            }
132
133
                            $buffer = '';
134
                            continue 3;
135
                    }
136
137
                case ',':
138
                    switch ($this->status()) {
139
                        case 'function':
140
                            if (($argument = self::prepareArgument($buffer))) {
141
                                $bufferFunctions[0][2][] = $argument;
142
                            }
143
144
                            $buffer = '';
145
                            continue 3;
146
                    }
147
148
                case ' ':
149
                case '\t':
150
                    switch ($this->status()) {
151
                        case 'double-quote':
152
                        case 'simple-quote':
153
                            break;
154
155
                        default:
156
                            continue 3;
157
                    }
158
                    break;
159
            }
160
161
            switch ($this->status()) {
162
                case 'line-comment':
163
                case 'block-comment':
164
                    break;
165
166
                default:
167
                    $buffer .= $char;
168
                    break;
169
            }
170
        }
171
172
        return $functions;
173
    }
174
175
    /**
176
     * Get the current context of the scan.
177
     *
178
     * @param null|string $match To check whether the current status is this value
179
     *
180
     * @return string|bool
181
     */
182
    protected function status($match = null)
183
    {
184
        $status = isset($this->status[0]) ? $this->status[0] : null;
185
186
        if ($match !== null) {
187
            return $status === $match;
188
        }
189
190
        return $status;
191
    }
192
193
    /**
194
     * Add a new status to the stack.
195
     *
196
     * @param string $status
197
     */
198
    protected function downStatus($status)
199
    {
200
        array_unshift($this->status, $status);
201
    }
202
203
    /**
204
     * Removes and return the current status.
205
     *
206
     * @return string|null
207
     */
208
    protected function upStatus()
209
    {
210
        return array_shift($this->status);
211
    }
212
213
    /**
214
     * Prepares the arguments found in functions.
215
     *
216
     * @param string $argument
217
     *
218
     * @return string
219
     */
220
    protected static function prepareArgument($argument)
221
    {
222
        if ($argument && ($argument[0] === '"' || $argument[0] === "'")) {
223
            if ($argument[0] === '"') {
224
                $argument = str_replace('\\"', '"', $argument);
225
            } else {
226
                $argument = str_replace("\\'", "'", $argument);
227
            }
228
229
            return substr($argument, 1, -1);
230
        }
231
    }
232
}
233