Completed
Push — master ( 5df011...747e00 )
by Changwan
03:50
created

ArrayList::__toString()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 21
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 7
nop 0
dl 0
loc 21
ccs 16
cts 16
cp 1
crap 7
rs 7.551
c 0
b 0
f 0
1
<?php
2
namespace Wandu\Collection;
3
4
use InvalidArgumentException;
5
use Traversable;
6
use Wandu\Collection\Contracts\ListInterface;
7
8
class ArrayList implements ListInterface
9
{
10
    /** @var \Traversable */
11
    protected $iterator;
12
13
    /** @var array */
14
    protected $items;
15
16
    /**
17
     * @param array|\Traversable $items
18
     */
19 49
    public function __construct($items = [])
20
    {
21 49
        if ($items instanceof Traversable) {
22 2
            $this->iterator = $items; // for lazy iterate
23
        } else {
24 48
            $this->items = array_values($items);
25
        }
26 49
    }
27
28
    /**
29
     * {@inheritdoc}
30
     */
31 1
    public function __toString()
32
    {
33 1
        $string = static::class . " [\n";
34 1
        foreach ($this as $item) {
35 1
            $string .= "    ";
36 1
            if (is_string($item)) {
37 1
                $string .= "\"{$item}\",\n";
38 1
            } elseif (is_scalar($item)) {
39 1
                $string .= "{$item},\n";
40 1
            } elseif (is_null($item)) {
41 1
                $string .= "null,\n";
42 1
            } elseif (is_array($item)) {
43 1
                $string .= "[array],\n";
44 1
            } elseif (is_object($item)) {
45 1
                $string .= "[" . get_class($item) . "],\n";
46
            } else {
47 1
                $string .= "[unknown],\n";
48
            }
49
        }
50 1
        return $string . ']';
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56 42
    public function toArray()
57
    {
58 42
        $arr = [];
59 42
        foreach ($this as $item) {
60 42
            if (method_exists($item, 'toArray')) {
61 1
                $arr[] = $item->toArray();
62
            } else {
63 42
                $arr[] = $item;
64
            }
65
        }
66 42
        return $arr;
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72 22
    public function all()
73
    {
74 22
        $this->executeIterator();
75 22
        return $this->items;
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81 7
    public function count()
82
    {
83 7
        $this->executeIterator();
84 7
        return count($this->items);
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90 1
    function jsonSerialize()
91
    {
92 1
        return $this->all(); // safe
93
    }
94
    
95
    /**
96
     * {@inheritdoc}
97
     */
98 47
    public function getIterator()
99
    {
100 47
        if (isset($this->iterator)) {
101 3
            $this->items = [];
102 3
            foreach ($this->iterator as $item) {
103 3
                yield $this->items[] = $item;
104
            }
105 3
            $this->iterator = null;
106 3
            return;
107
        }
108 46
        foreach ($this->items as $item) {
109 46
            yield $item;
110
        }
111 46
    }
112
113
    /**
114
     * {@inheritdoc}
115
     */
116 1
    public function offsetExists($offset)
117
    {
118 1
        $this->executeIterator();
119 1
        return isset($this->items[$offset]);
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125 2
    public function offsetGet($offset)
126
    {
127 2
        return $this->get($offset);
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 4
    public function offsetSet($offset, $value)
134
    {
135 4
        $this->assertIsNullOrIntegerLessSize($offset, __METHOD__);
136 4
        $this->set($offset, $value);
137 4
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142 1
    public function offsetUnset($offset)
143
    {
144 1
        $this->remove($offset);
145 1
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150 1
    public function serialize()
151
    {
152 1
        $this->executeIterator();
153 1
        return serialize($this->items);
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159 1
    public function unserialize($serialized)
160
    {
161 1
        $this->items = unserialize($serialized);
162 1
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function clear()
168
    {
169
        $this->iterator = null;
170
        $this->items = [];
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176 3
    public function contains(...$values)
177
    {
178 3
        $this->executeIterator();
179 3
        foreach ($values as $value) {
180 3
            if (!in_array($value, $this->items, true)) {
181 3
                return false;
182
            }
183
        }
184 3
        return true;
185
    }
186
187
    /**
188
     * {@inheritdoc}
189
     */
190 3
    public function get($key, $default = null)
191
    {
192 3
        $this->executeIterator();
193 3
        return array_key_exists($key, $this->items) ? $this->items[$key] : $default;
194
    }
195
196
    /**
197
     * {@inheritdoc}
198
     */
199 6
    public function set($key, $value)
200
    {
201 6
        $this->executeIterator();
202 6
        if (isset($key)) {
203 3
            $this->items[$key + 0] = $value;
204
        } else {
205 4
            $this->items[] = $value;
206
        }
207 6
    }
208
209
    /**
210
     * {@inheritdoc}
211
     */
212 2
    public function remove(...$keys)
213
    {
214 2
        $this->executeIterator();
215 2
        foreach ($keys as $key) {
216 2
            unset($this->items[$key]);
217
        }
218 2
        $this->items = array_values($this->items);
219 2
    }
220
221
    /**
222
     * {@inheritdoc}
223
     */
224 1
    public function has(...$keys)
225
    {
226 1
        $this->executeIterator();
227 1
        foreach ($keys as $key) {
228 1
            if (!array_key_exists($key, $this->items)) {
229 1
                return false;
230
            }
231
        }
232 1
        return true;
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238 1
    public function filter(callable $handler = null)
239
    {
240 1
        $this->executeIterator();
241 1
        if ($handler) {
242 1
            if (defined("ARRAY_FILTER_USE_BOTH")) {
243 1
                return new ArrayList(array_values(array_filter($this->items, $handler, ARRAY_FILTER_USE_BOTH)));
244
            } else {
245
                return new ArrayList(array_values(array_filter($this->items, $handler)));
246
            }
247
        }
248 1
        return new ArrayList(array_values(array_filter($this->items)));
249
    }
250
251
    /**
252
     * {@inheritdoc}
253
     */
254 1
    public function map(callable $handler)
255
    {
256 1
        $this->executeIterator();
257 1
        return new ArrayList(array_map($handler, $this->items, array_keys($this->items)));
258
    }
259
260
    /**
261
     * {@inheritdoc}
262
     */
263 1
    public function reduce(callable $handler, $initial = null)
264
    {
265 1
        foreach ($this as $key => $item) {
266 1
            $initial = $handler($initial, $item, $key);
267
        }
268 1
        return $initial;
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274 2
    public function groupBy(callable $handler)
275
    {
276 2
        $new = [];
277 2
        foreach ($this as $key => $item) {
278 2
            $groupName = call_user_func($handler, $item, $key);
279 2
            if (!isset($new[$groupName])) {
280 2
                $new[$groupName] = new ArrayList();
281
            }
282 2
            $new[$groupName][] = $item;
283
        }
284 2
        return new ArrayMap($new);
285
    }
286
287
    /**
288
     * {@inheritdoc}
289
     */
290 2
    public function keyBy(callable $handler)
291
    {
292 2
        $new = [];
293 2
        foreach ($this as $key => $item) {
294 2
            $keyName = call_user_func($handler, $item, $key);
295 2
            $new[$keyName] = $item;
296
        }
297 2
        return new ArrayMap($new);
298
    }
299
300
    /**
301
     * {@inheritdoc}
302
     */
303 4
    public function combine(ListInterface $list)
304
    {
305 4
        $this->executeIterator();
306 4
        return new ArrayMap(array_combine($this->items, $list->all()));
307
    }
308
309
    /**
310
     * {@inheritdoc}
311
     */
312 2
    public function first(callable $handler = null, $default = null)
313
    {
314 2
        $this->executeIterator();
315 2
        if ($handler) {
316 2
            foreach ($this->items as $key => $item) {
317 2
                if (call_user_func($handler, $item, $key)) {
318 2
                    return $item;
319
                }
320
            }
321 2
            return $default;
322
        }
323 2
        return isset($this->items[0]) ? $this->items[0] : $default;
324
    }
325
326
    /**
327
     * {@inheritdoc}
328
     */
329 2
    public function last(callable $handler = null, $default = null)
330
    {
331 2
        $this->executeIterator();
332 2
        if ($handler) {
333 2
            $length = count($this->items);
334 2
            for ($i = 0; $i < $length; $i++) {
335 2
                $key = $length - $i - 1;
336 2
                $item = $this->items[$key];
337 2
                if (call_user_func($handler, $item, $key)) {
338 2
                    return $item;
339
                }
340
            }
341 2
            return $default;
342
        }
343 2
        return ($length = count($this->items)) ? $this->items[$length - 1] : $default;
344
    }
345
346
    /**
347
     * {@inheritdoc}
348
     */
349 8
    public function intersect(ListInterface $list)
350
    {
351 8
        $this->executeIterator();
352 8
        return new ArrayList(array_intersect($this->items, $list->all()));
353
    }
354
355
    /**
356
     * {@inheritdoc}
357
     */
358 4
    public function union(ListInterface $list)
359
    {
360 4
        $this->executeIterator();
361 4
        return new ArrayList(array_unique_union($this->items, $list->all()));
362
    }
363
364
    /**
365
     * {@inheritdoc}
366
     */
367 4
    public function merge(ListInterface $list)
368
    {
369 4
        $this->executeIterator();
370 4
        return new ArrayList(array_merge($this->items, $list->all()));
371
    }
372
373
    /**
374
     * {@inheritdoc}
375
     */
376 2
    public function implode($glue = null)
377
    {
378 2
        $this->executeIterator();
379 2
        return implode($glue, $this->items);
380
    }
381
382
    /**
383
     * {@inheritdoc}
384
     */
385 2
    public function isEmpty()
386
    {
387 2
        return $this->count() === 0;
388
    }
389
390
    /**
391
     * {@inheritdoc}
392
     */
393 3
    public function pop()
394
    {
395 3
        $this->executeIterator();
396 3
        return array_pop($this->items);
397
    }
398
399
    /**
400
     * {@inheritdoc}
401
     */
402 1
    public function push(...$values)
403
    {
404 1
        $this->executeIterator();
405 1
        $this->items = array_merge($this->items, $values);
406 1
        return $this;
407
    }
408
409
    /**
410
     * {@inheritdoc}
411
     */
412 1
    public function shift()
413
    {
414 1
        $this->executeIterator();
415 1
        return array_shift($this->items);
416
    }
417
418
    /**
419
     * {@inheritdoc}
420
     */
421 1
    public function unshift(...$values)
422
    {
423 1
        $this->executeIterator();
424 1
        $this->items = array_merge(array_reverse($values), $this->items);
425 1
        return $this;
426
    }
427
428
    /**
429
     * {@inheritdoc}
430
     */
431 2
    public function reverse()
432
    {
433 2
        $this->executeIterator();
434 2
        return new ArrayList(array_reverse($this->items));
435
    }
436
437
    /**
438
     * {@inheritdoc}
439
     */
440 2
    public function shuffle()
441
    {
442 2
        $this->executeIterator();
443 2
        $items = $this->items;
444 2
        shuffle($items);
445 2
        return new ArrayList($items);
446
    }
447
448
    /**
449
     * {@inheritdoc}
450
     */
451 1
    public function sort(callable $callback = null)
452
    {
453 1
        $this->executeIterator();
454 1
        $items = $this->items;
455 1
        if ($callback) {
456 1
            usort($items, $callback);
457
        } else {
458 1
            sort($items);
459
        }
460 1
        return new ArrayList($items);
461
    }
462
    
463
    /**
464
     * {@inheritdoc}
465
     */
466 2
    public function slice($offset, $length = null)
467
    {
468 2
        $this->executeIterator();
469 2
        return new ArrayList(array_slice($this->items, $offset, $length));
470
    }
471
472
    /**
473
     * {@inheritdoc}
474
     */
475 4
    public function splice($offset, $length = null, $replacement = null)
476
    {
477 4
        $this->executeIterator();
478 4
        if ($length) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $length of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
479 2
            return new ArrayList(array_splice($this->items, $offset, $length, $replacement));
480
        }
481 2
        return new ArrayList(array_splice($this->items, $offset));
482
    }
483
    
484
    /**
485
     * {@inheritdoc}
486
     */
487 1
    public function unique()
488
    {
489 1
        $this->executeIterator();
490 1
        return new ArrayList(array_unique($this->items));
491
    }
492
    
493
    /**
494
     * @param mixed $value
495
     * @param string $method
496
     * @param int $order
497
     */
498 4
    private function assertIsNullOrIntegerLessSize($value, $method, $order = 1)
499
    {
500 4
        if (!isset($value)) {
501 4
            return;
502
        }
503 1
        if (is_int($value) && $value <= $this->count()) {
504 1
            return;
505
        }
506 1
        if (is_string($value)) {
507 1
            if ($value == (($value + 0) . '') && $value <= $this->count()) {
508
                return;
509
            }
510
        }
511 1
        throw new InvalidArgumentException("Argument {$order} passed to {$method} must be null or an integer less than the size of the list");
512
    }
513
    
514 55
    private function executeIterator()
515
    {
516 55
        if (isset($this->iterator)) {
517 25
            $this->items = iterator_to_array($this->iterator);
518 25
            $this->iterator = null;
519
        }
520 55
    }
521
}
522