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) |
|
|
|
|
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 self($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 self(\substr($this->raw, $start)); |
82
|
|
|
} |
83
|
|
|
return new self(\substr($this->raw, $start, $length)); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
public function nextToken($delim) |
87
|
|
|
{ |
88
|
|
|
if ($this->token) { |
89
|
|
|
return new self(\strtok($delim)); |
90
|
|
|
} |
91
|
|
|
$this->token = true; |
92
|
|
|
return new self(\strtok($this->raw, $delim)); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
// MODIFYING METHODS |
96
|
|
|
|
97
|
|
|
public function append($str) |
98
|
|
|
{ |
99
|
|
|
return $this->replaceWhole($this->raw . $str); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
public function chunk($length = 76, $ending = "\r\n") |
103
|
|
|
{ |
104
|
|
|
return $this->replaceWhole(\chunk_split($this->raw, $length, $ending)); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
public function concat($str) |
108
|
|
|
{ |
109
|
|
|
return $this->append($str); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
public function escape($flags = self::NORMAL, $charlist = '') |
113
|
|
|
{ |
114
|
|
|
// strip out bits we don't understand |
115
|
|
|
$flags &= (self::C_STYLE | self::META); |
116
|
|
|
|
117
|
|
|
$flagsmap = [ |
118
|
|
|
self::NORMAL => 'addslashes', |
119
|
|
|
self::C_STYLE => 'addcslashes', |
120
|
|
|
self::META => 'quotemeta', |
121
|
|
|
]; |
122
|
|
|
if ($flags === self::C_STYLE) { |
123
|
|
|
return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw, $charlist)); |
124
|
|
|
} |
125
|
|
|
return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw)); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
public function hexDecode() |
129
|
|
|
{ |
130
|
|
|
return $this->replaceWhole(\hex2bin($this->raw)); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
public function hexEncode() |
134
|
|
|
{ |
135
|
|
|
return $this->replaceWhole(\bin2hex($this->raw)); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
public function insertAt($str, $offset) |
139
|
|
|
{ |
140
|
|
|
return $this->replaceSubstr($str, $offset, 0); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
public function pad($newlength, $padding = ' ', $flags = self::END) |
144
|
|
|
{ |
145
|
|
|
return $this->replaceWhole(\str_pad($this->raw, $newlength, $padding, $flags)); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
public function prepend($str) |
149
|
|
|
{ |
150
|
|
|
return $this->replaceWhole($str . $this->raw); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
public function remove($str, $flags = self::NORMAL) |
154
|
|
|
{ |
155
|
|
|
return $this->replace($str, '', $flags); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
public function removeSubstr($start, $length = null) |
159
|
|
|
{ |
160
|
|
|
return $this->replaceSubstr('', $start, $length); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
public function repeat($times) |
164
|
|
|
{ |
165
|
|
|
return $this->replaceWhole(\str_repeat($this->raw, $times)); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @param string $replace |
170
|
|
|
*/ |
171
|
|
|
public function replace($search, $replace, $flags = self::NORMAL) |
172
|
|
|
{ |
173
|
|
|
if ($flags & self::CASE_INSENSITIVE) { |
174
|
|
|
return $this->replaceWhole(\str_ireplace($search, $replace, $this->raw)); |
175
|
|
|
} |
176
|
|
|
return $this->replaceWhole(\str_replace($search, $replace, $this->raw)); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
public function replaceSubstr($replacement, $start, $length = null) |
180
|
|
|
{ |
181
|
|
|
if ($length === null) { |
182
|
|
|
$length = $this->length(); |
183
|
|
|
} |
184
|
|
|
return $this->replaceWhole(\substr_replace($this->raw, $replacement, $start, $length)); |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
public function resetToken() |
188
|
|
|
{ |
189
|
|
|
$this->token = false; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
public function reverse() |
193
|
|
|
{ |
194
|
|
|
return $this->replaceWhole(\strrev($this->raw)); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
public function shuffle() |
198
|
|
|
{ |
199
|
|
|
return $this->replaceWhole(\str_shuffle($this->raw)); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
public function times($times) |
203
|
|
|
{ |
204
|
|
|
return $this->repeat($times); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
public function translate($search, $replace = '') |
208
|
|
|
{ |
209
|
|
|
if (is_array($search)) { |
210
|
|
|
return $this->replaceWhole(\strtr($this->raw, $search)); |
211
|
|
|
} |
212
|
|
|
return $this->replaceWhole(\strtr($this->raw, $search, $replace)); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
View Code Duplication |
public function trim($mask = " \t\n\r\0\x0B", $flags = self::BOTH_ENDS) |
216
|
|
|
{ |
217
|
|
|
// strip out bits we don't understand |
218
|
|
|
$flags &= (self::END | self::BOTH_ENDS); |
219
|
|
|
|
220
|
|
|
$flagsmap = [ |
221
|
|
|
self::START => 'ltrim', |
222
|
|
|
self::END => 'rtrim', |
223
|
|
|
self::BOTH_ENDS => 'trim', |
224
|
|
|
]; |
225
|
|
|
return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw, $mask)); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
View Code Duplication |
public function unescape($flags = self::NORMAL) |
229
|
|
|
{ |
230
|
|
|
// strip out bits we don't understand |
231
|
|
|
$flags &= (self::C_STYLE | self::META); |
232
|
|
|
|
233
|
|
|
$flagsmap = [ |
234
|
|
|
self::NORMAL => 'stripslashes', |
235
|
|
|
self::C_STYLE => 'stripcslashes', |
236
|
|
|
self::META => 'stripslashes', |
237
|
|
|
]; |
238
|
|
|
return $this->replaceWhole(\call_user_func($flagsmap[$flags], $this->raw)); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
public function uuDecode() |
242
|
|
|
{ |
243
|
|
|
return $this->replaceWhole(\convert_uudecode($this->raw)); |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
public function uuEncode() |
247
|
|
|
{ |
248
|
|
|
return $this->replaceWhole(\convert_uuencode($this->raw)); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
public function wordwrap($width = 75, $break = "\n") |
252
|
|
|
{ |
253
|
|
|
return $this->replaceWhole(\wordwrap($this->raw, $width, $break, false)); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
public function wordwrapBreaking($width = 75, $break = "\n") |
257
|
|
|
{ |
258
|
|
|
return $this->replaceWhole(\wordwrap($this->raw, $width, $break, true)); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
// TESTING METHODS |
262
|
|
|
|
263
|
|
|
public function contains($needle, $offset = 0, $flags = self::NORMAL) |
264
|
|
|
{ |
265
|
|
|
if ($flags & self::EXACT_POSITION) { |
266
|
|
|
return ($this->indexOf($needle, $offset, $flags) === $offset); |
267
|
|
|
} |
268
|
|
|
return ($this->indexOf($needle, $offset, $flags) !== false); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
public function countSubstr($needle, $offset = 0, $length = null) |
272
|
|
|
{ |
273
|
|
|
if ($length === null) { |
274
|
|
|
return \substr_count($this->raw, $needle, $offset); |
275
|
|
|
} |
276
|
|
|
return \substr_count($this->raw, $needle, $offset, $length); |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
public function endsWith($str, $flags = self::NORMAL) |
280
|
|
|
{ |
281
|
|
|
$flags &= self::CASE_INSENSITIVE; |
282
|
|
|
$offset = $this->length() - \strlen($str); |
283
|
|
|
return $this->contains($str, $offset, $flags | self::EXACT_POSITION | self::REVERSE); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
public function equals($str) |
287
|
|
|
{ |
288
|
|
|
self::testStringableObject($str); |
289
|
|
|
|
290
|
|
|
$str = (string) $str; |
291
|
|
|
return ($str == $this->raw); |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
public function isAscii() |
295
|
|
|
{ |
296
|
|
|
$len = $this->length(); |
297
|
|
|
|
298
|
|
|
for ($i = 0; $i < $len; $i++) { |
299
|
|
|
if ($this->charCodeAt($i) >= 128) { |
300
|
|
|
return false; |
301
|
|
|
} |
302
|
|
|
} |
303
|
|
|
return true; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
public function isEmpty() |
307
|
|
|
{ |
308
|
|
|
return empty($this->raw); |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
public function startsWith($str, $flags = self::NORMAL) |
312
|
|
|
{ |
313
|
|
|
$flags &= self::CASE_INSENSITIVE; |
314
|
|
|
return $this->contains($str, 0, $flags | self::EXACT_POSITION); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
// INTERFACE IMPLEMENTATION METHODS |
318
|
|
|
|
319
|
|
|
public function count() |
320
|
|
|
{ |
321
|
|
|
return \strlen($this->raw); |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
public function current() |
325
|
|
|
{ |
326
|
|
|
return $this->raw[$this->caret]; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
public function offsetGet($offset) |
330
|
|
|
{ |
331
|
|
|
return $this->raw{$offset}; |
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
public function offsetSet($offset, $value) |
335
|
|
|
{ |
336
|
|
|
throw new \LogicException('Cannot assign ' . $value . ' to immutable AString instance at index ' . $offset); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
public function offsetUnset($offset) |
340
|
|
|
{ |
341
|
|
|
throw new \LogicException('Cannot unset index ' . $offset . ' on immutable AString instance'); |
342
|
|
|
} |
343
|
|
|
} |
344
|
|
|
|
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.