These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | declare(strict_types = 1); |
||
3 | |||
4 | namespace Innmind\Immutable; |
||
5 | |||
6 | use Innmind\Immutable\{ |
||
7 | Exception\OutOfBoundException, |
||
8 | Exception\LogicException, |
||
9 | Exception\ElementNotFoundException, |
||
10 | Exception\GroupEmptySequenceException |
||
11 | }; |
||
12 | |||
13 | /** |
||
14 | * A defined set of ordered elements |
||
15 | */ |
||
16 | class Sequence implements SequenceInterface |
||
17 | { |
||
18 | private $values; |
||
19 | private $size; |
||
20 | |||
21 | 63 | public function __construct(...$values) |
|
22 | { |
||
23 | 63 | $this->values = $values; |
|
24 | 63 | $this->size = count($values); |
|
25 | 63 | } |
|
26 | |||
27 | /** |
||
28 | * {@inheritdoc} |
||
29 | */ |
||
30 | 24 | public function size(): int |
|
31 | { |
||
32 | 24 | return $this->size; |
|
33 | } |
||
34 | |||
35 | /** |
||
36 | * {@inheritdoc} |
||
37 | */ |
||
38 | 1 | public function count(): int |
|
39 | { |
||
40 | 1 | return $this->size(); |
|
41 | } |
||
42 | |||
43 | /** |
||
44 | * {@inheritdoc} |
||
45 | */ |
||
46 | 6 | public function current() |
|
47 | { |
||
48 | 6 | return current($this->values); |
|
49 | } |
||
50 | |||
51 | /** |
||
52 | * {@inheritdoc} |
||
53 | */ |
||
54 | 8 | public function key() |
|
55 | { |
||
56 | 8 | return key($this->values); |
|
57 | } |
||
58 | |||
59 | /** |
||
60 | * {@inheritdoc} |
||
61 | */ |
||
62 | 8 | public function next() |
|
63 | { |
||
64 | 8 | next($this->values); |
|
65 | 8 | } |
|
66 | |||
67 | /** |
||
68 | * {@inheritdoc} |
||
69 | */ |
||
70 | 6 | public function rewind() |
|
71 | { |
||
72 | 6 | reset($this->values); |
|
73 | 6 | } |
|
74 | |||
75 | /** |
||
76 | * {@inheritdoc} |
||
77 | */ |
||
78 | 6 | public function valid(): bool |
|
79 | { |
||
80 | 6 | return $this->key() !== null; |
|
81 | } |
||
82 | |||
83 | /** |
||
84 | * {@inheritdoc} |
||
85 | */ |
||
86 | 1 | public function offsetExists($offset): bool |
|
87 | { |
||
88 | 1 | return array_key_exists($offset, $this->values); |
|
89 | } |
||
90 | |||
91 | /** |
||
92 | * {@inheritdoc} |
||
93 | */ |
||
94 | 1 | public function offsetGet($offset) |
|
95 | { |
||
96 | 1 | if (!$this->offsetExists($offset)) { |
|
97 | throw new OutOfBoundException(sprintf( |
||
98 | 'Unknown index %s', |
||
99 | $offset |
||
100 | )); |
||
101 | } |
||
102 | |||
103 | 1 | return $this->values[$offset]; |
|
104 | } |
||
105 | |||
106 | /** |
||
107 | * {@inheritdoc} |
||
108 | */ |
||
109 | 1 | public function offsetSet($offset, $value) |
|
110 | { |
||
111 | 1 | throw new LogicException('You can\'t modify a sequence'); |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * {@inheritdoc} |
||
116 | */ |
||
117 | 1 | public function offsetUnset($offset) |
|
118 | { |
||
119 | 1 | throw new LogicException('You can\'t modify a sequence'); |
|
120 | } |
||
121 | |||
122 | /** |
||
123 | * {@inheritdoc} |
||
124 | */ |
||
125 | 25 | public function toPrimitive() |
|
126 | { |
||
127 | 25 | return $this->values; |
|
128 | } |
||
129 | |||
130 | /** |
||
131 | * {@inheritdoc} |
||
132 | */ |
||
133 | 14 | public function get(int $index) |
|
134 | { |
||
135 | 14 | if ($index >= $this->size()) { |
|
136 | 1 | throw new OutOfBoundException; |
|
137 | } |
||
138 | |||
139 | 13 | return $this->values[$index]; |
|
140 | } |
||
141 | |||
142 | /** |
||
143 | * {@inheritdoc} |
||
144 | */ |
||
145 | 1 | public function diff(SequenceInterface $seq): SequenceInterface |
|
146 | { |
||
147 | 1 | return new self( |
|
148 | 1 | ...array_diff( |
|
149 | 1 | $this->values, |
|
150 | 1 | $seq->toPrimitive() |
|
151 | ) |
||
152 | ); |
||
153 | } |
||
154 | |||
155 | /** |
||
156 | * {@inheritdoc} |
||
157 | */ |
||
158 | 1 | public function distinct(): SequenceInterface |
|
159 | { |
||
160 | 1 | return new self(...array_unique($this->values)); |
|
161 | } |
||
162 | |||
163 | /** |
||
164 | * {@inheritdoc} |
||
165 | */ |
||
166 | 5 | public function drop(int $size): SequenceInterface |
|
167 | { |
||
168 | 5 | return new self(...array_slice($this->values, $size)); |
|
169 | } |
||
170 | |||
171 | /** |
||
172 | * {@inheritdoc} |
||
173 | */ |
||
174 | 2 | public function dropEnd(int $size): SequenceInterface |
|
175 | { |
||
176 | 2 | return new self(...array_slice($this->values, 0, $this->size() - $size)); |
|
177 | } |
||
178 | |||
179 | /** |
||
180 | * {@inheritdoc} |
||
181 | */ |
||
182 | 3 | public function equals(SequenceInterface $seq): bool |
|
183 | { |
||
184 | 3 | return $this->values === $seq->toPrimitive(); |
|
185 | } |
||
186 | |||
187 | /** |
||
188 | * {@inheritdoc} |
||
189 | */ |
||
190 | 1 | public function filter(\Closure $predicate): SequenceInterface |
|
191 | { |
||
192 | 1 | return new self(...array_filter( |
|
193 | 1 | $this->values, |
|
194 | $predicate |
||
195 | )); |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * {@inheritdoc} |
||
200 | */ |
||
201 | 1 | public function foreach(\Closure $function): SequenceInterface |
|
202 | { |
||
203 | 1 | foreach ($this->values as $value) { |
|
204 | 1 | $function($value); |
|
205 | } |
||
206 | |||
207 | 1 | return $this; |
|
208 | } |
||
209 | |||
210 | /** |
||
211 | * {@inheritdoc} |
||
212 | */ |
||
213 | 2 | public function groupBy(\Closure $discriminator): MapInterface |
|
214 | { |
||
215 | 2 | if ($this->size() === 0) { |
|
216 | 1 | throw new GroupEmptySequenceException; |
|
217 | } |
||
218 | |||
219 | 1 | $map = null; |
|
220 | |||
221 | 1 | foreach ($this->values as $value) { |
|
222 | 1 | $key = $discriminator($value); |
|
223 | |||
224 | 1 | View Code Duplication | if ($map === null) { |
225 | 1 | $type = gettype($key); |
|
226 | 1 | $map = new Map( |
|
227 | 1 | $type === 'object' ? get_class($key) : $type, |
|
228 | 1 | SequenceInterface::class |
|
229 | ); |
||
230 | } |
||
231 | |||
232 | 1 | View Code Duplication | if ($map->contains($key)) { |
0 ignored issues
–
show
|
|||
233 | 1 | $map = $map->put( |
|
234 | $key, |
||
235 | 1 | $map->get($key)->add($value) |
|
236 | ); |
||
237 | } else { |
||
238 | 1 | $map = $map->put($key, new Sequence($value)); |
|
239 | } |
||
240 | } |
||
241 | |||
242 | 1 | return $map; |
|
243 | } |
||
244 | |||
245 | /** |
||
246 | * {@inheritdoc} |
||
247 | */ |
||
248 | 2 | public function first() |
|
249 | { |
||
250 | 2 | return $this->values[0]; |
|
251 | } |
||
252 | |||
253 | /** |
||
254 | * {@inheritdoc} |
||
255 | */ |
||
256 | 2 | public function last() |
|
257 | { |
||
258 | 2 | return $this->values[$this->size() - 1]; |
|
259 | } |
||
260 | |||
261 | /** |
||
262 | * {@inheritdoc} |
||
263 | */ |
||
264 | 25 | public function contains($element): bool |
|
265 | { |
||
266 | 25 | return in_array($element, $this->values, true); |
|
267 | } |
||
268 | |||
269 | /** |
||
270 | * {@inheritdoc} |
||
271 | */ |
||
272 | 9 | public function indexOf($element): int |
|
273 | { |
||
274 | 9 | $index = array_search($element, $this->values); |
|
275 | |||
276 | 9 | if ($index === false) { |
|
277 | 1 | throw new ElementNotFoundException; |
|
278 | } |
||
279 | |||
280 | 8 | return $index; |
|
281 | } |
||
282 | |||
283 | /** |
||
284 | * {@inheritdoc} |
||
285 | */ |
||
286 | 1 | public function indices(): SequenceInterface |
|
287 | { |
||
288 | 1 | return new self(...array_keys($this->values)); |
|
289 | } |
||
290 | |||
291 | /** |
||
292 | * {@inheritdoc} |
||
293 | */ |
||
294 | 1 | public function map(\Closure $function): SequenceInterface |
|
295 | { |
||
296 | 1 | return new self(...array_map($function, $this->values)); |
|
297 | } |
||
298 | |||
299 | /** |
||
300 | * {@inheritdoc} |
||
301 | */ |
||
302 | 1 | public function pad(int $size, $element): SequenceInterface |
|
303 | { |
||
304 | 1 | return new self(...array_pad($this->values, $size, $element)); |
|
305 | } |
||
306 | |||
307 | /** |
||
308 | * {@inheritdoc} |
||
309 | */ |
||
310 | 1 | public function partition(\Closure $predicate): SequenceInterface |
|
311 | { |
||
312 | 1 | $truthy = []; |
|
313 | 1 | $falsy = []; |
|
314 | |||
315 | 1 | foreach ($this->values as $value) { |
|
316 | 1 | if ($predicate($value) === true) { |
|
317 | 1 | $truthy[] = $value; |
|
318 | } else { |
||
319 | 1 | $falsy[] = $value; |
|
320 | } |
||
321 | } |
||
322 | |||
323 | 1 | return new self( |
|
324 | 1 | new self(...$truthy), |
|
325 | 1 | new self(...$falsy) |
|
326 | ); |
||
327 | } |
||
328 | |||
329 | /** |
||
330 | * {@inheritdoc} |
||
331 | */ |
||
332 | 9 | public function slice(int $from, int $until): SequenceInterface |
|
333 | { |
||
334 | 9 | return new self(...array_slice( |
|
335 | 9 | $this->values, |
|
336 | $from, |
||
337 | 9 | $until - $from |
|
338 | )); |
||
339 | } |
||
340 | |||
341 | /** |
||
342 | * {@inheritdoc} |
||
343 | */ |
||
344 | 1 | public function splitAt(int $index): SequenceInterface |
|
345 | { |
||
346 | 1 | return new self( |
|
347 | 1 | $this->slice(0, $index), |
|
348 | 1 | $this->slice($index, $this->size()) |
|
349 | ); |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * {@inheritdoc} |
||
354 | */ |
||
355 | 5 | public function take(int $size): SequenceInterface |
|
356 | { |
||
357 | 5 | return $this->slice(0, $size); |
|
358 | } |
||
359 | |||
360 | /** |
||
361 | * {@inheritdoc} |
||
362 | */ |
||
363 | 2 | public function takeEnd(int $size): SequenceInterface |
|
364 | { |
||
365 | 2 | return $this->slice($this->size() - $size, $this->size()); |
|
366 | } |
||
367 | |||
368 | /** |
||
369 | * {@inheritdoc} |
||
370 | */ |
||
371 | 4 | public function append(SequenceInterface $seq): SequenceInterface |
|
372 | { |
||
373 | 4 | return new self(...$this->values, ...$seq->toPrimitive()); |
|
374 | } |
||
375 | |||
376 | /** |
||
377 | * {@inheritdoc} |
||
378 | */ |
||
379 | 1 | public function intersect(SequenceInterface $seq): SequenceInterface |
|
380 | { |
||
381 | 1 | return new self(...array_intersect($this->values, $seq->toPrimitive())); |
|
382 | } |
||
383 | |||
384 | /** |
||
385 | * {@inheritdoc} |
||
386 | */ |
||
387 | 2 | public function join(string $separator): StringPrimitive |
|
388 | { |
||
389 | 2 | return new StringPrimitive(implode($separator, $this->values)); |
|
390 | } |
||
391 | |||
392 | /** |
||
393 | * {@inheritdoc} |
||
394 | */ |
||
395 | 23 | public function add($element): SequenceInterface |
|
396 | { |
||
397 | 23 | $values = $this->values; |
|
398 | 23 | $values[] = $element; |
|
399 | |||
400 | 23 | return new self(...$values); |
|
401 | } |
||
402 | } |
||
403 |
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.