Completed
Push — master ( 87ca00...34571b )
by Changwan
06:15
created

ArrayList::toArray()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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