Completed
Push — master ( ef76cc...010027 )
by Garrett
02:18
created

AString   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 295
Duplicated Lines 12.54 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 7
Bugs 0 Features 1
Metric Value
wmc 50
c 7
b 0
f 1
lcom 1
cbo 1
dl 37
loc 295
rs 8.6206

37 Methods

Rating   Name   Duplication   Size   Complexity  
A toArray() 13 13 4
A charAt() 0 4 1
A charCodeAt() 0 4 1
A compareTo() 0 20 2
A indexOf() 0 13 1
A length() 0 4 1
A substr() 0 7 2
A append() 0 4 1
A chunk() 0 4 1
A escape() 0 15 2
A insertAt() 0 4 1
A pad() 0 4 1
A prepend() 0 4 1
A remove() 0 4 1
A removeSubstr() 0 4 1
A repeat() 0 4 1
A replace() 0 7 2
A replaceSubstr() 0 7 2
A reverse() 0 4 1
A shuffle() 0 4 1
A translate() 0 7 2
A trim() 12 12 1
A unescape() 12 12 1
A wordwrap() 0 4 1
A wordwrapBreaking() 0 4 1
A contains() 0 7 2
A countSubstr() 0 7 2
A endsWith() 0 6 1
A equals() 0 7 1
A isAscii() 0 11 3
A isEmpty() 0 4 1
A startsWith() 0 5 1
A count() 0 4 1
A current() 0 4 1
A offsetGet() 0 4 1
A offsetSet() 0 4 1
A offsetUnset() 0 4 1

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 AString 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 AString, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace StringObject;
4
5
class AString extends AnyString
6
{
7
    protected $token = false;
8
9 View Code Duplication
    public function toArray($delim = '', $limit = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
10
    {
11
        if (empty($delim)) {
12
            return \str_split($this->raw);
13
        }
14
        if (is_int($delim)) {
15
            return \str_split($this->raw, $delim);
16
        }
17
        if ($limit === null) {
18
            return \explode($delim, $this->raw);
19
        }
20
        return \explode($delim, $this->raw, $limit);
21
    }
22
23
    // INFORMATIONAL METHODS
24
25
    public function charAt($offset)
26
    {
27
        return new static($this->raw{$offset});
28
    }
29
30
    /**
31
     * @param integer $offset
32
     */
33
    public function charCodeAt($offset)
34
    {
35
        return \ord($this->raw{$offset});
36
    }
37
38
    public function compareTo($str, $flags = self::NORMAL, $length = 1)
39
    {
40
        // strip out bits we don't understand
41
        $flags &= (self::CASE_INSENSITIVE | self::CURRENT_LOCALE | self::NATURAL_ORDER | self::FIRST_N);
42
43
        $flagsmap = [
44
            self::NORMAL => 'strcmp',
45
            self::CASE_INSENSITIVE => 'strcasecmp',
46
            self::CURRENT_LOCALE => 'strcoll',
47
            self::NATURAL_ORDER => 'strnatcmp',
48
            (self::NATURAL_ORDER | self::CASE_INSENSITIVE) => 'strnatcasecmp',
49
            self::FIRST_N => 'strncmp',
50
            (self::FIRST_N | self::CASE_INSENSITIVE) => 'strncasecmp',
51
        ];
52
53
        if ($flags & self::FIRST_N) {
54
            return \call_user_func($flagsmap[$flags], $this->raw, $str, $length);
55
        }
56
        return \call_user_func($flagsmap[$flags], $this->raw, $str);
57
    }
58
59
    public function indexOf($needle, $offset = 0, $flags = self::NORMAL)
60
    {
61
        // strip out bits we don't understand
62
        $flags &= (self::REVERSE | self::CASE_INSENSITIVE);
63
64
        $flagsmap = [
65
            self::NORMAL => 'strpos',
66
            self::CASE_INSENSITIVE => 'stripos',
67
            self::REVERSE => 'strrpos',
68
            (self::REVERSE | self::CASE_INSENSITIVE) => 'strripos',
69
        ];
70
        return \call_user_func($flagsmap[$flags], $this->raw, $needle, $offset);
71
    }
72
73
    public function length()
74
    {
75
        return \strlen($this->raw);
76
    }
77
78
    public function substr($start, $length = 'omitted')
79
    {
80
        if ($length === 'omitted') {
81
            return new static(\substr($this->raw, $start));
82
        }
83
        return new static(\substr($this->raw, $start, $length));
84
    }
85
86
    // MODIFYING METHODS
87
88
    public function append($str)
89
    {
90
        return $this->replaceWhole($this->raw . $str);
91
    }
92
93
    public function chunk($length = 76, $ending = "\r\n")
94
    {
95
        return $this->replaceWhole(\chunk_split($this->raw, $length, $ending));
96
    }
97
98
    public function escape($flags = self::NORMAL, $charlist = '')
99
    {
100
        // strip out bits we don't understand
101
        $flags &= (self::C_STYLE | self::META);
102
103
        $flagsmap = [
104
            self::NORMAL => 'addslashes',
105
            self::C_STYLE => 'addcslashes',
106
            self::META => 'quotemeta',
107
        ];
108
        if ($flags === self::C_STYLE) {
109
            return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw, $charlist));
110
        }
111
        return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw));
112
    }
113
114
    public function insertAt($str, $offset)
115
    {
116
        return $this->replaceSubstr($str, $offset, 0);
117
    }
118
119
    public function pad($newlength, $padding = ' ', $flags = self::END)
120
    {
121
        return $this->replaceWhole(\str_pad($this->raw, $newlength, $padding, $flags));
122
    }
123
124
    public function prepend($str)
125
    {
126
        return $this->replaceWhole($str . $this->raw);
127
    }
128
129
    public function remove($str, $flags = self::NORMAL)
130
    {
131
        return $this->replace($str, '', $flags);
132
    }
133
134
    public function removeSubstr($start, $length = null)
135
    {
136
        return $this->replaceSubstr('', $start, $length);
137
    }
138
139
    public function repeat($times)
140
    {
141
        return $this->replaceWhole(\str_repeat($this->raw, $times));
142
    }
143
144
    /**
145
     * @param string $replace
146
     */
147
    public function replace($search, $replace, $flags = self::NORMAL)
148
    {
149
        if ($flags & self::CASE_INSENSITIVE) {
150
            return $this->replaceWhole(\str_ireplace($search, $replace, $this->raw));
151
        }
152
        return $this->replaceWhole(\str_replace($search, $replace, $this->raw));
153
    }
154
155
    public function replaceSubstr($replacement, $start, $length = null)
156
    {
157
        if ($length === null) {
158
            $length = $this->length();
159
        }
160
        return $this->replaceWhole(\substr_replace($this->raw, $replacement, $start, $length));
161
    }
162
163
    public function reverse()
164
    {
165
        return $this->replaceWhole(\strrev($this->raw));
166
    }
167
168
    public function shuffle()
169
    {
170
        return $this->replaceWhole(\str_shuffle($this->raw));
171
    }
172
173
    public function translate($search, $replace = '')
174
    {
175
        if (is_array($search)) {
176
            return $this->replaceWhole(\strtr($this->raw, $search));
177
        }
178
        return $this->replaceWhole(\strtr($this->raw, $search, $replace));
179
    }
180
181 View Code Duplication
    public function trim($mask = " \t\n\r\0\x0B", $flags = self::BOTH_ENDS)
182
    {
183
        // strip out bits we don't understand
184
        $flags &= (self::END | self::BOTH_ENDS);
185
186
        $flagsmap = [
187
            self::START => 'ltrim',
188
            self::END => 'rtrim',
189
            self::BOTH_ENDS => 'trim',
190
        ];
191
        return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw, $mask));
192
    }
193
194 View Code Duplication
    public function unescape($flags = self::NORMAL)
195
    {
196
        // strip out bits we don't understand
197
        $flags &= (self::C_STYLE | self::META);
198
199
        $flagsmap = [
200
            self::NORMAL => 'stripslashes',
201
            self::C_STYLE => 'stripcslashes',
202
            self::META => 'stripslashes',
203
        ];
204
        return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw));
205
    }
206
207
    public function wordwrap($width = 75, $break = "\n")
208
    {
209
        return $this->replaceWhole(\wordwrap($this->raw, $width, $break, false));
210
    }
211
212
    public function wordwrapBreaking($width = 75, $break = "\n")
213
    {
214
        return $this->replaceWhole(\wordwrap($this->raw, $width, $break, true));
215
    }
216
217
    // TESTING METHODS
218
219
    public function contains($needle, $offset = 0, $flags = self::NORMAL)
220
    {
221
        if ($flags & self::EXACT_POSITION) {
222
            return ($this->indexOf($needle, $offset, $flags) === $offset);
223
        }
224
        return ($this->indexOf($needle, $offset, $flags) !== false);
225
    }
226
227
    public function countSubstr($needle, $offset = 0, $length = null)
228
    {
229
        if ($length === null) {
230
            return \substr_count($this->raw, $needle, $offset);
231
        }
232
        return \substr_count($this->raw, $needle, $offset, $length);
233
    }
234
235
    public function endsWith($str, $flags = self::NORMAL)
236
    {
237
        $flags &= self::CASE_INSENSITIVE;
238
        $offset = $this->length() - \strlen($str);
239
        return $this->contains($str, $offset, $flags | self::EXACT_POSITION | self::REVERSE);
240
    }
241
242
    public function equals($str)
243
    {
244
        self::testStringableObject($str);
245
246
        $str = (string) $str;
247
        return ($str == $this->raw);
248
    }
249
250
    public function isAscii()
251
    {
252
        $len = $this->length();
253
254
        for ($i = 0; $i < $len; $i++) {
255
            if ($this->charCodeAt($i) >= 128) {
256
                return false;
257
            }
258
        }
259
        return true;
260
    }
261
262
    public function isEmpty()
263
    {
264
        return empty($this->raw);
265
    }
266
267
    public function startsWith($str, $flags = self::NORMAL)
268
    {
269
        $flags &= self::CASE_INSENSITIVE;
270
        return $this->contains($str, 0, $flags | self::EXACT_POSITION);
271
    }
272
273
    // INTERFACE IMPLEMENTATION METHODS
274
275
    public function count()
276
    {
277
        return \strlen($this->raw);
278
    }
279
280
    public function current()
281
    {
282
        return $this->raw[$this->caret];
283
    }
284
285
    public function offsetGet($offset)
286
    {
287
        return $this->raw{$offset};
288
    }
289
290
    public function offsetSet($offset, $value)
291
    {
292
        throw new \LogicException('Cannot assign ' . $value . ' to immutable AString instance at index ' . $offset);
293
    }
294
295
    public function offsetUnset($offset)
296
    {
297
        throw new \LogicException('Cannot unset index ' . $offset . ' on immutable AString instance');
298
    }
299
}
300