Completed
Push — master ( 3daf45...3860d5 )
by Garrett
11:11
created

StrObj::findUtf8CharAt()   C

Complexity

Conditions 17
Paths 17

Size

Total Lines 69
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 69
rs 5.6439
cc 17
eloc 34
nc 17
nop 1

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 StringObject;
4
5
class StrObj implements \ArrayAccess, \Countable, \Iterator
6
{
7
    // CONSTANTS
8
9
    const NORMAL = 0;
10
    const START = 0;
11
    const END = 1;
12
    const BOTH_ENDS = 2;
13
    const CASE_INSENSITIVE = 4;
14
    const REVERSE = 8;
15
    const EXACT_POSITION = 16;
16
    const CURRENT_LOCALE = 32;
17
    const NATURAL_ORDER = 64;
18
    const FIRST_N = 128;
19
    const C_STYLE = 256;
20
    const META = 512;
21
    const LAZY = 1024;
22
    const GREEDY = 2048;
23
24
    // STATIC PROPERTIES
25
26
    protected static $asciimap = [
27
        'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ', 'â', 'ấ',
28
                'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ',
29
                'ἄ', 'ἅ', 'ἆ', 'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ',
30
                'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ'],
31
        'b' => ['б', 'β', 'Ъ', 'Ь', 'ب'],
32
        'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ'],
33
        'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض'],
34
        'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ë', 'ē',
35
                'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ',
36
                'έ', 'е', 'ё', 'э', 'є', 'ə'],
37
        'f' => ['ф', 'φ', 'ف'],
38
        'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ج'],
39
        'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه'],
40
        'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', 'ı', 'ι', 'ί',
41
                'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ',
42
                'ῑ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'і', 'ї', 'и'],
43
        'j' => ['ĵ', 'ј', 'Ј'],
44
        'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك'],
45
        'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل'],
46
        'm' => ['м', 'μ', 'م'],
47
        'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن'],
48
        'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ơ', 'ớ',
49
                'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ',
50
                'ὄ', 'ὅ', 'ὸ', 'ό', 'о', 'و', 'θ'],
51
        'p' => ['п', 'π'],
52
        'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر'],
53
        's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص'],
54
        't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط'],
55
        'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'û', 'ū',
56
                'ů', 'ű', 'ŭ', 'ų', 'µ', 'у'],
57
        'v' => ['в'],
58
        'w' => ['ŵ', 'ω', 'ώ'],
59
        'x' => ['χ'],
60
        'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي'],
61
        'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز'],
62
        'aa' => ['ع'],
63
        'ae' => ['ä', 'æ'],
64
        'ch' => ['ч'],
65
        'dj' => ['ђ', 'đ'],
66
        'dz' => ['џ'],
67
        'gh' => ['غ'],
68
        'kh' => ['х', 'خ'],
69
        'lj' => ['љ'],
70
        'nj' => ['њ'],
71
        'oe' => ['ö', 'œ'],
72
        'ps' => ['ψ'],
73
        'sh' => ['ш'],
74
        'shch' => ['щ'],
75
        'ss' => ['ß'],
76
        'th' => ['þ', 'ث', 'ذ', 'ظ'],
77
        'ts' => ['ц'],
78
        'ue' => ['ü'],
79
        'ya' => ['я'],
80
        'yu' => ['ю'],
81
        'zh' => ['ж'],
82
        '(c)' => ['©'],
83
        'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ', 'Â', 'Ấ',
84
                'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ',
85
                'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ',
86
                'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А'],
87
        'B' => ['Б', 'Β'],
88
        'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ'],
89
        'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ'],
90
        'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ë', 'Ē',
91
                'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ',
92
                'Ὲ', 'Е', 'Ё', 'Э', 'Є', 'Ə'],
93
        'F' => ['Ф', 'Φ'],
94
        'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ'],
95
        'H' => ['Η', 'Ή'],
96
        'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', 'İ', 'Ι', 'Ί',
97
                'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И',
98
                'І', 'Ї'],
99
        'K' => ['К', 'Κ'],
100
        'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ'],
101
        'M' => ['М', 'Μ'],
102
        'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν'],
103
        'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ơ', 'Ớ',
104
                'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ',
105
                'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', 'Ό', 'О', 'Θ', 'Ө'],
106
        'P' => ['П', 'Π'],
107
        'R' => ['Ř', 'Ŕ', 'Р', 'Ρ'],
108
        'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ'],
109
        'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ'],
110
        'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Û', 'Ū',
111
                'Ů', 'Ű', 'Ŭ', 'Ų', 'У'],
112
        'V' => ['В'],
113
        'W' => ['Ω', 'Ώ'],
114
        'X' => ['Χ'],
115
        'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ'],
116
        'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ'],
117
        'AE' => ['Ä', 'Æ'],
118
        'CH' => ['Ч'],
119
        'DJ' => ['Ђ'],
120
        'DZ' => ['Џ'],
121
        'KH' => ['Х'],
122
        'LJ' => ['Љ'],
123
        'NJ' => ['Њ'],
124
        'OE' => ['Ö'],
125
        'PS' => ['Ψ'],
126
        'SH' => ['Ш'],
127
        'SHCH' => ['Щ'],
128
        'SS' => ['ẞ'],
129
        'TH' => ['Þ'],
130
        'TS' => ['Ц'],
131
        'UE' => ['Ü'],
132
        'YA' => ['Я'],
133
        'YU' => ['Ю'],
134
        'ZH' => ['Ж'],
135
        ' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82",
136
                "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86",
137
                "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A",
138
                "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80"],
139
    ];
140
141
    // PROPERTIES
142
143
    protected $raw;
144
    protected $token = false;
145
    protected $caret = 0;
146
147
    // MAGIC METHODS
148
149
    public function __construct($thing)
150
    {
151
        self::testStringableObject($thing);
152
153
        if (\is_array($thing)) {
154
            throw new \InvalidArgumentException('Unsure of how to convert array to string');
155
        }
156
157
        $this->raw = (string) $thing;
158
    }
159
160
    /**
161
     * @return mixed
162
     */
163
    public function __get($name)
164
    {
165
        return $this->$name;
166
    }
167
168
    /**
169
     * @return string
170
     */
171
    public function __toString()
172
    {
173
        return $this->raw;
174
    }
175
176 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...
177
    {
178
        if (empty($delim)) {
179
            return \str_split($this->raw);
180
        }
181
        if (is_int($delim)) {
182
            return \str_split($this->raw, $delim);
183
        }
184
        if ($limit === null) {
185
            return \explode($delim, $this->raw);
186
        }
187
        return \explode($delim, $this->raw, $limit);
188
    }
189
190
    // INFORMATIONAL METHODS
191
192
    public function charAt($offset)
193
    {
194
        return new self($this->raw{$offset});
195
    }
196
197
    /**
198
     * @param integer $offset
199
     */
200
    public function charCodeAt($offset)
201
    {
202
        return \ord($this->raw{$offset});
203
    }
204
205
    public function compareTo($str, $mode = self::NORMAL, $length = 1)
206
    {
207
        $modemap = [
208
            self::NORMAL => 'strcmp',
209
            self::CASE_INSENSITIVE => 'strcasecmp',
210
            self::CURRENT_LOCALE => 'strcoll',
211
            self::NATURAL_ORDER => 'strnatcmp',
212
            (self::NATURAL_ORDER | self::CASE_INSENSITIVE) => 'strnatcasecmp',
213
            self::FIRST_N => 'strncmp',
214
            (self::FIRST_N | self::CASE_INSENSITIVE) => 'strncasecmp',
215
        ];
216
217
        if ($mode & self::FIRST_N) {
218
            return \call_user_func($modemap[$mode], $this->raw, $str, $length);
219
        }
220
        return \call_user_func($modemap[$mode], $this->raw, $str);
221
    }
222
223
    public function indexOf($needle, $offset = 0, $mode = self::NORMAL)
224
    {
225
        // strip out bits we don't understand
226
        $mode &= (self::REVERSE | self::CASE_INSENSITIVE);
227
228
        $modemap = [
229
            self::NORMAL => 'strpos',
230
            self::CASE_INSENSITIVE => 'stripos',
231
            self::REVERSE => 'strrpos',
232
            (self::REVERSE | self::CASE_INSENSITIVE) => 'strripos',
233
        ];
234
        return \call_user_func($modemap[$mode], $this->raw, $needle, $offset);
235
    }
236
237
    public function length()
238
    {
239
        return \strlen($this->raw);
240
    }
241
242
    // MODIFYING METHODS
243
244
    public function append($str)
245
    {
246
        return new self($this->raw . $str);
247
    }
248
249
    public function asciify($removeUnsupported = true)
250
    {
251
        $str = $this->raw;
252
        foreach (self::$asciimap as $key => $value) {
253
            $str = \str_replace($value, $key, $str);
254
        }
255
        if ($removeUnsupported) {
256
            $str = \preg_replace('/[^\x20-\x7E]/u', '', $str);
257
        }
258
        return new self($str);
259
    }
260
261
    public function chunk($length = 76, $ending = "\r\n")
262
    {
263
        return new self(\chunk_split($this->raw, $length, $ending));
264
    }
265
266
    public function concat($str)
267
    {
268
        return $this->append($str);
269
    }
270
271
    public function escape($mode = self::NORMAL, $charlist = '')
272
    {
273
        $modemap = [
274
            self::NORMAL => 'addslashes',
275
            self::C_STYLE => 'addcslashes',
276
            self::META => 'quotemeta',
277
        ];
278
        if ($mode === self::C_STYLE) {
279
            return new self(\call_user_func($modemap[$mode], $this->raw, $charlist));
280
        }
281
        return new self(\call_user_func($modemap[$mode], $this->raw));
282
    }
283
284
    public function insertAt($str, $offset)
285
    {
286
        return $this->replaceSubstr($str, $offset, 0);
287
    }
288
289
    public function nextToken($delim)
290
    {
291
        if ($this->token) {
292
            return new self(\strtok($delim));
293
        }
294
        $this->token = true;
295
        return new self(\strtok($this->raw, $delim));
296
    }
297
298
    public function pad($newlength, $padding = ' ', $mode = self::END)
299
    {
300
        return new self(\str_pad($this->raw, $newlength, $padding, $mode));
301
    }
302
303
    public function prepend($str)
304
    {
305
        return new self($str . $this->raw);
306
    }
307
308
    public function remove($str, $mode = self::NORMAL)
309
    {
310
        return $this->replace($str, '', $mode);
311
    }
312
313
    public function removeSubstr($start, $length = null)
314
    {
315
        return $this->replaceSubstr('', $start, $length);
316
    }
317
318
    public function repeat($times)
319
    {
320
        return new self(\str_repeat($this->raw, $times));
321
    }
322
323
    /**
324
     * @param string $replace
325
     */
326
    public function replace($search, $replace, $mode = self::NORMAL)
327
    {
328
        if ($mode & self::CASE_INSENSITIVE) {
329
            return new self(\str_ireplace($search, $replace, $this->raw));
330
        }
331
        return new self(\str_replace($search, $replace, $this->raw));
332
    }
333
334
    public function replaceSubstr($replacement, $start, $length = null)
335
    {
336
        if ($length === null) {
337
            $length = $this->length();
338
        }
339
        return new self(\substr_replace($this->raw, $replacement, $start, $length));
340
    }
341
342
    public function resetToken()
343
    {
344
        $this->token = false;
345
    }
346
347
    public function reverse()
348
    {
349
        return new self(\strrev($this->raw));
350
    }
351
352
    public function shuffle()
353
    {
354
        return new self(\str_shuffle($this->raw));
355
    }
356
357
    public function substr($start, $length = 'omitted')
358
    {
359
        if ($length === 'omitted') {
360
            return new self(\substr($this->raw, $start));
361
        }
362
        return new self(\substr($this->raw, $start, $length));
363
    }
364
365
    public function times($times)
366
    {
367
        return $this->repeat($times);
368
    }
369
370
    public function translate($search, $replace = '')
371
    {
372
        if (is_array($search)) {
373
            return new self(\strtr($this->raw, $search));
374
        }
375
        return new self(\strtr($this->raw, $search, $replace));
376
    }
377
378
    public function trim($mask = " \t\n\r\0\x0B", $mode = self::BOTH_ENDS)
379
    {
380
        $modemap = [
381
            self::START => 'ltrim',
382
            self::END => 'rtrim',
383
            self::BOTH_ENDS => 'trim',
384
        ];
385
        return new self(\call_user_func($modemap[$mode], $this->raw, $mask));
386
    }
387
388
    public function unescape($mode = self::NORMAL)
389
    {
390
        $modemap = [
391
            self::NORMAL => 'stripslashes',
392
            self::C_STYLE => 'stripcslashes',
393
            self::META => 'stripslashes',
394
        ];
395
        return new self(\call_user_func($modemap[$mode], $this->raw));
396
    }
397
398
    public function uuDecode()
399
    {
400
        return new self(\convert_uudecode($this->raw));
401
    }
402
403
    public function uuEncode()
404
    {
405
        return new self(\convert_uuencode($this->raw));
406
    }
407
408
    public function wordwrap($width = 75, $break = "\n")
409
    {
410
        return new self(\wordwrap($this->raw, $width, $break, false));
411
    }
412
413
    public function wordwrapBreaking($width = 75, $break = "\n")
414
    {
415
        return new self(\wordwrap($this->raw, $width, $break, true));
416
    }
417
418
    // TESTING METHODS
419
420
    public function contains($needle, $offset = 0, $mode = self::NORMAL)
421
    {
422
        if ($mode & self::EXACT_POSITION) {
423
            return ($this->indexOf($needle, $offset, $mode) === $offset);
424
        }
425
        return ($this->indexOf($needle, $offset, $mode) !== false);
426
    }
427
428
    public function countSubstr($needle, $offset = 0, $length = null)
429
    {
430
        if ($length === null) {
431
            return \substr_count($this->raw, $needle, $offset);
432
        }
433
        return \substr_count($this->raw, $needle, $offset, $length);
434
    }
435
436
    public function endsWith($str, $mode = self::NORMAL)
437
    {
438
        $mode &= self::CASE_INSENSITIVE;
439
        $offset = $this->length() - \strlen($str);
440
        return $this->contains($str, $offset, $mode | self::EXACT_POSITION | self::REVERSE);
441
    }
442
443
    public function equals($str)
444
    {
445
        self::testStringableObject($str);
446
447
        $str = (string) $str;
448
        return ($str == $this->raw);
449
    }
450
451
    public function isAscii()
452
    {
453
        $len = $this->length();
454
455
        for ($i = 0; $i < $len; $i++) {
456
            if ($this->charCodeAt($i) >= 128) {
457
                return false;
458
            }
459
        }
460
        return true;
461
    }
462
463
    public function isEmpty()
464
    {
465
        return empty($this->raw);
466
    }
467
468
    public function startsWith($str, $mode = self::NORMAL)
469
    {
470
        $mode &= self::CASE_INSENSITIVE;
471
        return $this->contains($str, 0, $mode | self::EXACT_POSITION);
472
    }
473
474
    // INTERFACE IMPLEMENTATION METHODS
475
476
    public function count()
477
    {
478
        return \strlen($this->raw);
479
    }
480
481
    public function current()
482
    {
483
        return $this->raw[$this->caret];
484
    }
485
486
    public function key()
487
    {
488
        return $this->caret;
489
    }
490
491
    public function next()
492
    {
493
        $this->caret++;
494
    }
495
496
    public function rewind()
497
    {
498
        $this->caret = 0;
499
    }
500
501
    public function valid()
502
    {
503
        return ($this->caret < \strlen($this->raw));
504
    }
505
506
    public function offsetExists($offset)
507
    {
508
        $offset = (int) $offset;
509
        return ($offset >= 0 && $offset < \strlen($this->raw));
510
    }
511
512
    public function offsetGet($offset)
513
    {
514
        return $this->raw{$offset};
515
    }
516
517
    public function offsetSet($offset, $value)
518
    {
519
        throw new \LogicException('Cannot assign '.$value.' to immutable StrObj instance at index '.$offset);
520
    }
521
522
    public function offsetUnset($offset)
523
    {
524
        throw new \LogicException('Cannot unset index '.$offset.' on immutable StrObj instance');
525
    }
526
527
    // PRIVATE STATIC FUNCTIONS
528
529
    protected static function testStringableObject($thing)
530
    {
531
        if (\is_object($thing) && !\method_exists($thing, '__toString')) {
532
            throw new \InvalidArgumentException(
533
                'Parameter is an object that does not implement __toString() method'
534
            );
535
        }
536
    }
537
}
538