Completed
Push — master ( 19af0c...93d685 )
by Luke
08:44
created

Collection::key()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
namespace Noz\Collection;
3
4
use Countable;
5
use JsonSerializable;
6
use Iterator;
7
use ArrayAccess;
8
use RuntimeException;
9
use Traversable;
10
11
use function Noz\is_traversable,
12
             Noz\to_array;
13
14
/**
15
 * Nozavroni Collection
16
 *
17
 * Basically an array wrapper with a bunch of super useful methods for working with its items and/or create new collections from its items.
18
 *
19
 * @note None of the methods in this class have a $preserveKeys param. That is by design. I don't think it's necessary.
20
 *       Instead, keys are ALWAYS preserved and if you want to NOT preserve keys, simply call Collection::values().
21
 * @todo Scour Laravel's collection methods for ideas (for instance contains($val, $key) to check key as well as value)
22
 *       So I did and the following methods look interesting (think about implementing): tap, times, transform, zip?
23
 *       I also still like the idea of a pairs() method that returns a collection of the collection's key/val pairs as
24
 *       two-item arrays [key, val].
25
 */
26
class Collection implements ArrayAccess, Iterator, Countable, JsonSerializable
27
{
28
    /** @var array */
29
    protected $items;
30
31
    /**
32
     * Collection constructor.
33
     *
34
     * @param array $items
35
     */
36 93
    public function __construct(array $items = [])
37
    {
38 93
        $this->items = $items;
39 93
        $this->rewind();
40 93
    }
41
42
    /**
43
     * Generate a collection from an array of items.
44
     * I created this method so that it's possible to extend a collection more easily.
45
     *
46
     * @param mixed $items
47
     *
48
     * @return Collection
49
     */
50 30
    public static function factory($items = null)
51
    {
52 30
        if (is_null($items)) {
53 10
            $items = [];
54 10
        }
55 30
        return new Collection(to_array($items));
56
    }
57
58
    /**
59
     * Get collection as an array
60
     *
61
     * @return array
62
     */
63 47
    public function toArray()
64
    {
65 47
        return $this->items;
66
    }
67
68
    /**
69
     * Determine if collection has a given key
70
     *
71
     * @param mixed $key The key to look for
72
     *
73
     * @return bool
74
     */
75 47
    public function has($key)
76
    {
77 47
        return isset($this->items[$key]) || array_key_exists($key, $this->items);
78
    }
79
80
    /**
81
     * Does collection have item at position?
82
     *
83
     * Determine if collection has an item at a particular position (indexed from one).
84
     * Position can be positive and start from the beginning or it can be negative and
85
     * start from the end.
86
     *
87
     * @param int $position
88
     *
89
     * @return bool
90
     */
91 2
    public function hasValueAt($position)
92
    {
93
        try {
94 2
            $this->getKeyAt($position);
95 2
            return true;
96 2
        } catch (RuntimeException $e) {
97 2
            return false;
98
        }
99
    }
100
101
    /**
102
     * Get key at given position
103
     *
104
     * Returns the key at the given position, starting from one. Position can be positive (start from beginning) or
105
     * negative (start from the end).
106
     *
107
     * If the position does not exist, a RuntimeException is thrown.
108
     *
109
     * @param int $position
110
     *
111
     * @return string
112
     *
113
     * @throws RuntimeException
114
     */
115 6
    public function getKeyAt($position)
116
    {
117 6
        $collection = $this;
118 6
        if ($position < 0) {
119 3
            $collection = $this->reverse();
120 3
        }
121 6
        $i = 1;
122 6
        foreach ($collection as $key => $val) {
123 6
            if (abs($position) == $i++) {
124 5
                return $key;
125
            }
126 6
        }
127 3
        throw new RuntimeException("No key at position {$position}");
128
    }
129
130
    /**
131
     * Get value at given position
132
     *
133
     * Returns the value at the given position, starting from one. Position can be positive (start from beginning) or
134
     * negative (start from the end).
135
     *
136
     * If the position does not exist, a RuntimeException is thrown.
137
     *
138
     * @param int $position
139
     *
140
     * @return mixed
141
     *
142
     * @throws RuntimeException
143
     */
144 2
    public function getValueAt($position)
145
    {
146 2
        return $this->get($this->getKeyAt($position));
147
    }
148
149
    /**
150
     * Get the key of the first item found matching $item
151
     *
152
     * @todo should this throw an exception if not found?
153
     *
154
     * @param mixed|callable $item
155
     *
156
     * @return mixed|null
157
     */
158 2
    public function keyOf($item)
159
    {
160 2
        $index = 0;
161 2
        foreach ($this as $key => $val) {
162 2
            if (is_callable($item)) {
163 1
                if ($item($val, $key, $index++)) {
164 1
                    return $key;
165
                }
166 2
            } elseif ($item === $val) {
167 1
                return $key;
168
            }
169 2
        }
170
171 1
        return null;
172
    }
173
174
    /**
175
     * Get the offset (index) of the first item found that matches $item
176
     *
177
     * @todo should this throw an exception if not found?
178
     *
179
     * @param mixed|callable $item
180
     *
181
     * @return int|null
182
     */
183 2
    public function indexOf($item)
184
    {
185 2
        $index = 0;
186 2
        foreach ($this as $key => $val) {
187 2
            if (is_callable($item)) {
188 1
                if ($item($val, $key, $index)) {
189 1
                    return $index;
190
                }
191 1
            } else {
192 1
                if ($item === $val) {
193 1
                    return $index;
194
                }
195
            }
196 2
            $index++;
197 2
        }
198
199 1
        return null;
200
    }
201
202
    /**
203
     * Get item by key, with an optional default return value
204
     *
205
     * @param mixed $key
206
     * @param mixed $default
207
     *
208
     * @return mixed
209
     */
210 8
    public function get($key, $default = null)
211
    {
212 8
        if ($this->has($key)) {
213 8
            return $this->items[$key];
214
        }
215
216 3
        return $default;
217
    }
218
219
    /**
220
     * Add an item with no regard to key
221
     *
222
     * @param mixed $value
223
     *
224
     * @return $this
225
     */
226 8
    public function add($value)
227
    {
228 8
        $this->items[] = $value;
229
230 8
        return $this;
231
    }
232
233
    /**
234
     * Set an item at a given key
235
     *
236
     * @param mixed $key
237
     * @param mixed $value
238
     * @param bool  $overwrite If false, do not overwrite existing key
239
     *
240
     * @return $this
241
     */
242 14
    public function set($key, $value, $overwrite = true)
243
    {
244 14
        if ($overwrite || !$this->has($key)) {
245 14
            $this->items[$key] = $value;
246 14
        }
247
248 14
        return $this;
249
    }
250
251
    /**
252
     * Delete an item by key
253
     *
254
     * @param mixed $key
255
     *
256
     * @return $this
257
     */
258 3
    public function delete($key)
259
    {
260 3
        unset($this->items[$key]);
261
262 3
        return $this;
263
    }
264
265
    /**
266
     * Clear the collection of all its items.
267
     *
268
     * @return $this
269
     */
270 2
    public function clear()
271
    {
272 2
        $this->items = [];
273
274 2
        return $this;
275
    }
276
277
    /**
278
     * Determine if collection contains given value
279
     *
280
     * @param mixed|callable $val
281
     * @param mixed $key
282
     *
283
     * @return bool
284
     */
285 4
    public function contains($val, $key = null)
286
    {
287 4
        $index = 0;
288 4
        foreach ($this as $k => $v) {
289 4
            $matchkey = is_null($key) || $key === $k;
290 4
            if (is_callable($val)) {
291 1
                if ($val($v, $k, $index)) {
292 1
                    return $matchkey;
293
                }
294 1
            } else {
295 3
                if ($val === $v) {
296 3
                    return $matchkey;
297
                }
298
            }
299 4
            $index++;
300 4
        }
301 2
        return false;
302
    }
303
304
    /**
305
     * Fetch item from collection by key and remove it from collection
306
     *
307
     * @param mixed $key
308
     *
309
     * @return mixed
310
     */
311 1
    public function pull($key)
312
    {
313 1
        if ($this->has($key)) {
314 1
            $value = $this->get($key);
315 1
            $this->delete($key);
316 1
            return $value;
317
        }
318 1
    }
319
320
    /**
321
     * Join collection items using a delimiter
322
     *
323
     * @param string $delim
324
     *
325
     * @return string
326
     */
327 1
    public function join($delim = '')
328
    {
329 1
        return implode($delim, $this->items);
330
    }
331
332
    /**
333
     * Determine if collection has any items
334
     *
335
     * @return bool
336
     */
337 4
    public function isEmpty()
338
    {
339 4
        return $this->count() == 0;
340
    }
341
342
    /**
343
     * Get a collection of only this collection's values (without its keys)
344
     *
345
     * @return Collection
346
     */
347 1
    public function values()
348
    {
349 1
        return static::factory(array_values($this->items));
350
    }
351
352
    /**
353
     * Get a collection of only this collection's keys
354
     *
355
     * @return Collection
356
     */
357 1
    public function keys()
358
    {
359 1
        return static::factory(array_keys($this->items));
360
    }
361
362
    /**
363
     * Get a collection with order reversed
364
     *
365
     * @return Collection
366
     */
367 6
    public function reverse()
368
    {
369 6
        return static::factory(array_reverse($this->items));
370
    }
371
372
    /**
373
     * Get a collection with keys and values flipped
374
     *
375
     * @return Collection
376
     */
377 1
    public function flip()
378
    {
379 1
        $collection = static::factory();
380 1
        foreach ($this as $key => $val) {
381 1
            $collection->set($val, $key);
382 1
        }
383 1
        return $collection;
384
    }
385
386
    /**
387
     * Shuffle the order of this collection's values
388
     *
389
     * @return Collection
390
     */
391 1
    public function shuffle()
392
    {
393 1
        shuffle($this->items);
394 1
        return $this;
395
    }
396
397
    /**
398
     * Get a random value from the collection
399
     * 
400
     * @todo might be useful to add a $count param to specify you want $count random items...
401
     *
402
     * @return mixed
403
     */
404 1
    public function random()
405
    {
406 1
        return $this->getValueAt(rand(1, $this->count()));
407
    }
408
409
    /**
410
     * Sort the collection (using values)
411
     *
412
     * @param callable $alg
413
     *
414
     * @return $this
415
     */
416 2
    public function sort(callable $alg = null)
417
    {
418 2
        if (is_null($alg)) {
419
            // case-sensitive string comparison is the default sorting mechanism
420 1
            $alg = 'strcmp';
421 1
        }
422 2
        uasort($this->items, $alg);
423
424 2
        return $this;
425
    }
426
427
    /**
428
     * Sort the collection (using keys)
429
     *
430
     * @param callable $alg
431
     *
432
     * @return $this
433
     */
434 2
    public function ksort(callable $alg = null)
435
    {
436 2
        if (is_null($alg)) {
437
            // case-sensitive string comparison is the default sorting mechanism
438 1
            $alg = 'strcmp';
439 1
        }
440 2
        uksort($this->items, $alg);
441
442 2
        return $this;
443
    }
444
445
    /**
446
     * Append items to collection without regard to keys
447
     *
448
     * @param array|Traversable $items
449
     *
450
     * @return $this
451
     */
452 2
    public function append($items)
453
    {
454 2
        if (!is_traversable($items)) {
455 1
            throw new RuntimeException("Invalid input type for " . __METHOD__ . ", must be array or Traversable");
456
        }
457
458 1
        foreach ($items as $val) {
459 1
            $this->add($val);
460 1
        }
461
462 1
        return $this;
463
    }
464
465
    /**
466
     * Return first item or first item where callback returns true
467
     *
468
     * @param callable|null $callback
469
     *
470
     * @return mixed|null
471
     */
472 7
    public function first(callable $callback = null)
473
    {
474 7
        $index = 0;
475 7
        foreach ($this as $key => $val) {
476 7
            if (is_null($callback) || $callback($val, $key, $index++)) {
477 7
                return $val;
478
            }
479 6
        }
480
481
        return null;
482
    }
483
484
    /**
485
     * Return last item or last item where callback returns true
486
     *
487
     * @param callable|null $callback
488
     *
489
     * @return mixed|null
490
     */
491 3
    public function last(callable $callback = null)
492
    {
493 3
        return $this->reverse()->first($callback);
494
    }
495
496
    /**
497
     * Map collection
498
     *
499
     * Create a new collection using the results of a callback function on each item in this collection.
500
     *
501
     * @param callable $callback
502
     *
503
     * @return Collection
504
     */
505 3
    public function map(callable $callback)
506
    {
507 3
        $collection = static::factory();
508
509 3
        $index = 0;
510 3
        foreach ($this as $key => $val) {
511 3
            $collection->set($key, $callback($val, $key, $index++));
512 3
        }
513
514 3
        return $collection;
515
    }
516
517
    /**
518
     * Combine collection with another traversable/collection
519
     *
520
     * Using this collection's keys, and the incoming collection's values, a new collection is created and returned.
521
     *
522
     * @param array|Traversable $items
523
     *
524
     * @return Collection
525
     */
526 5
    public function combine($items)
527
    {
528 5
        if (!is_traversable($items)) {
529 1
            throw new RuntimeException("Invalid input type for " . __METHOD__ . ", must be array or Traversable");
530
        }
531
532 4
        $items = to_array($items);
533 4
        if (count($items) != count($this->items)) {
534 1
            throw new RuntimeException("Invalid input for " . __METHOD__ . ", number of items does not match");
535
        }
536
537 3
        return static::factory(array_combine($this->items, $items));
538
    }
539
540
    /**
541
     * Get a new collection with only distinct values
542
     *
543
     * @return Collection
544
     */
545 1
    public function distinct()
546
    {
547 1
        $collection = static::factory();
548 1
        foreach ($this as $key => $val) {
549 1
            if (!$collection->contains($val)) {
550 1
                $collection->set($key, $val);
551 1
            }
552 1
        }
553
554 1
        return $collection;
555
    }
556
557
    /**
558
     * Remove all duplicate values from collection in-place
559
     *
560
     * @return Collection
561
     */
562 1
    public function deduplicate()
563
    {
564 1
        $this->items = array_unique($this->items);
565
566 1
        return $this;
567
    }
568
569
    /**
570
     * Return a new collection with only filtered keys/values
571
     *
572
     * The callback accepts value, key, index and should return true if the item should be added to the returned
573
     * collection
574
     *
575
     * @param callable $callback
576
     *
577
     * @return Collection
578
     */
579 2
    public function filter(callable $callback = null)
580
    {
581 2
        $collection = static::factory();
582 2
        $index = 0;
583 2
        foreach ($this as $key => $value) {
584 2
            if (is_null($callback)) {
585 1
                if ($value) {
586 1
                    $collection->set($key, $value);
587 1
                }
588 1
            } else {
589 1
                if ($callback($value, $key, $index++)) {
590 1
                    $collection->set($key, $value);
591 1
                }
592
            }
593 2
        }
594
595 2
        return $collection;
596
    }
597
598
    /**
599
     * Fold collection into a single value
600
     *
601
     * Loop through collection calling a callback function and passing the result to the next iteration, eventually
602
     * returning a single value.
603
     *
604
     * @param callable $callback
605
     * @param mixed $initial
606
     *
607
     * @return null
608
     */
609 1
    public function fold(callable $callback, $initial = null)
610
    {
611 1
        $index = 0;
612 1
        $folded = $initial;
613 1
        foreach ($this as $key => $val) {
614 1
            $folded = $callback($folded, $val, $key, $index++);
615 1
        }
616
617 1
        return $folded;
618
    }
619
620
    /**
621
     * Return a merge of this collection and $items
622
     *
623
     * @param array|Traversable $items
624
     *
625
     * @return Collection
626
     */
627 3
    public function merge($items)
628
    {
629 3
        if (!is_traversable($items)) {
630 1
            throw new RuntimeException("Invalid input type for " . __METHOD__ . ", must be array or Traversable");
631
        }
632
633 2
        $collection = clone $this;
634 2
        foreach ($items as $key => $val) {
635 2
            $collection->set($key, $val);
636 2
        }
637
638 2
        return $collection;
639
    }
640
641
    /**
642
     * Create a new collection with a union of this collection and $items
643
     *
644
     * This method is similar to merge, except that existing items will not be overwritten.
645
     *
646
     * @param $items
647
     */
648 2
    public function union($items)
649
    {
650 2
        if (!is_traversable($items)) {
651 1
            throw new RuntimeException("Invalid input type for " . __METHOD__ . ", must be array or Traversable");
652
        }
653
654 1
        $collection = clone $this;
655 1
        foreach ($items as $key => $val) {
656 1
            $collection->set($key, $val, false);
657 1
        }
658
659 1
        return $collection;
660
    }
661
662
    /**
663
     * Call callback for each item in collection, passively
664
     * If at any point the callback returns false, iteration stops.
665
     *
666
     * @param callable $callback
667
     *
668
     * @return $this
669
     */
670 2
    public function each(callable $callback)
671
    {
672 2
        $index = 0;
673 2
        foreach ($this as $key => $val) {
674 2
            if ($callback($val, $key, $index++) === false) {
675 1
                break;
676
            }
677 2
        }
678
679 2
        return $this;
680
    }
681
682
    /**
683
     * Assert callback returns $expected value for each item in collection.
684
     *
685
     * @todo This can be used to easily make methods like all($callback) and none($callback).
686
     *
687
     * @param callable $callback
688
     * @param bool $expected
689
     *
690
     * @return bool
691
     */
692 1
    public function assert(callable $callback, $expected = true)
693
    {
694 1
        $index = 0;
695 1
        foreach ($this as $key => $val) {
696 1
            if ($callback($val, $key, $index++) !== $expected) {
697 1
                return false;
698
            }
699 1
        }
700
701 1
        return true;
702
    }
703
704
    /**
705
     * Pipe collection through a callback
706
     *
707
     * @param callable $callback
708
     *
709
     * @return mixed
710
     */
711 1
    public function pipe(callable $callback)
712
    {
713 1
        return $callback($this);
714
    }
715
716
    /**
717
     * Get new collection in chunks of $size
718
     *
719
     * Creates a new collection of arrays of $size length. The remainder items will be placed at the end.
720
     *
721
     * @param int $size
722
     *
723
     * @return Collection
724
     */
725 2
    public function chunk($size)
726
    {
727 2
        return static::factory(array_chunk($this->items, $size, true));
728
    }
729
730
    /**
731
     * Get a new collection of $count chunks
732
     *
733
     * @todo It might be useful to have a method that spreads remainder items more evenly so you don't end up with the
734
     *       last item containing only one or two items.
735
     *
736
     * @param int $count
737
     *
738
     * @return Collection
739
     */
740 1
    public function split($count = 1)
741
    {
742 1
        return $this->chunk(ceil($this->count() / $count));
743
    }
744
745
    /**
746
     * Get a slice of this collection.
747
     *
748
     * @param int $offset
749
     * @param int|null $length
750
     *
751
     * @return Collection
752
     */
753 1
    public function slice($offset, $length = null)
754
    {
755 1
        return static::factory(array_slice($this->items, $offset, $length, true));
756
    }
757
758
    /**
759
     * Get collection with only differing items
760
     *
761
     * @param array|Traversable $items
762
     *
763
     * @return Collection
764
     */
765 1
    public function diff($items)
766
    {
767 1
        return static::factory(array_diff($this->items, to_array($items)));
768
    }
769
770
    /**
771
     * Get collection with only differing items (by key)
772
     *
773
     * @param array|Traversable $items
774
     *
775
     * @return Collection
776
     */
777 1
    public function kdiff($items)
778
    {
779 1
        return static::factory(array_diff_key($this->items, to_array($items)));
780
    }
781
782
    /**
783
     * Get collection with only intersecting items
784
     *
785
     * @param array|Traversable $items
786
     *
787
     * @return Collection
788
     */
789 1
    public function intersect($items)
790
    {
791 1
        return static::factory(array_intersect($this->items, to_array($items)));
792
    }
793
794
    /**
795
     * Get collection with only intersecting items (by key)
796
     *
797
     * @param array|Traversable $items
798
     *
799
     * @return Collection
800
     */
801 1
    public function kintersect($items)
802
    {
803 1
        return static::factory(array_intersect_key($this->items, to_array($items)));
804
    }
805
806
    /**
807
     * Remove last item in collection and return it
808
     *
809
     * @return mixed
810
     */
811 1
    public function pop()
812
    {
813 1
        return array_pop($this->items);
814
    }
815
816
    /**
817
     * Remove first item in collection and return it (and re-index if numerically indexed)
818
     *
819
     * @return mixed
820
     */
821 2
    public function shift()
822
    {
823 2
        return array_shift($this->items);
824
    }
825
826
    /**
827
     * Add item to the end of the collection
828
     *
829
     * @note This method is no different than add() but I included it for consistency's sake since I have the others
830
     *
831
     * @param mixed $item
832
     *
833
     * @return $this
834
     */
835 1
    public function push($item)
836
    {
837 1
        return $this->add($item);
838
    }
839
840
    /**
841
     * Add item to the beginning of the collection (and re-index if a numerically indexed collection)
842
     *
843
     * @param mixed $item
844
     *
845
     * @return $this
846
     */
847 5
    public function unshift($item)
848
    {
849 5
        array_unshift($this->items, $item);
850
851 5
        return $this;
852
    }
853
854
    /**
855
     * Get new collection padded to specified $size with $value
856
     *
857
     * Using $value, pad the collection to specified $size. If $size is smaller or equal to the size of the collection,
858
     * then no padding takes place. If $size is positive, padding is added to the end, while if negative, padding will
859
     * be added to the beginning.
860
     *
861
     * @param int $size
862
     * @param mixed $value
863
     *
864
     * @return Collection
865
     */
866 3
    public function pad($size, $value = null)
867
    {
868 3
        $collection = clone $this;
869 3
        while ($collection->count() < abs($size)) {
870 3
            if ($size > 0) {
871 3
                $collection->add($value);
872 3
            } else {
873 3
                $collection->unshift($value);
874
            }
875 3
        }
876
877 3
        return $collection;
878
    }
879
880
    /**
881
     * Partition collection into two collections using a callback
882
     *
883
     * Iterates over each element in the collection with a callback. Items where callback returns true are placed in one
884
     * collection and the rest in another. Finally, the two collections are placed in an array and returned for easy use
885
     * with the list() function. ( list($a, $b) = $col->partition(function($val, $key, $index) {}) )
886
     *
887
     * @param callable $callback
888
     *
889
     * @return array<Collection>
890
     */
891 2
    public function partition(callable $callback)
892
    {
893 2
        $pass = static::factory();
894 2
        $fail = static::factory();
895
896 2
        $index = 0;
897 2
        foreach ($this as $key => $val) {
898 1
            if ($callback($val, $key, $index++)) {
899 1
                $pass->set($key, $val);
900 1
            } else {
901 1
                $fail->set($key, $val);
902
            }
903 2
        }
904
905 2
        return [$pass, $fail];
906
    }
907
908
    /** ++++                  ++++ **/
909
    /** ++ Interface Compliance ++ **/
910
    /** ++++                  ++++ **/
911
912
    /**
913
     * @return array
914
     */
915 1
    public function jsonSerialize()
916
    {
917 1
        return $this->toArray();
918
    }
919
920
    /** ++++                  ++++ **/
921
    /** ++ Array Access Methods ++ **/
922
    /** ++++                  ++++ **/
923
924
    /**
925
     * {@inheritDoc}
926
     */
927 1
    public function offsetExists($offset)
928
    {
929 1
        return $this->has($offset);
930
    }
931
932
    /**
933
     * {@inheritDoc}
934
     */
935 2
    public function offsetGet($offset)
936
    {
937 2
        if (!$this->has($offset)) {
938 1
            throw new RuntimeException("Unknown offset: {$offset}");
939
        }
940
941 1
        return $this->get($offset);
942
    }
943
944
    /**
945
     * {@inheritDoc}
946
     */
947 1
    public function offsetUnset($offset)
948
    {
949 1
        $this->delete($offset);
950 1
    }
951
952
    /**
953
     * {@inheritDoc}
954
     */
955 1
    public function offsetSet($offset, $value)
956
    {
957 1
        if (!isset($offset)) {
958 1
            $this->add($value);
959 1
        }
960
961 1
        $this->set($offset, $value);
962 1
    }
963
964
    /** ++++                  ++++ **/
965
    /** ++   Iterator Methods   ++ **/
966
    /** ++++                  ++++ **/
967
968
    /**
969
     * {@inheritDoc}
970
     */
971 35
    public function current()
972
    {
973 35
        return current($this->items);
974
    }
975
976
    /**
977
     * {@inheritDoc}
978
     */
979 35
    public function key()
980
    {
981 35
        return key($this->items);
982
    }
983
984
    /**
985
     * {@inheritDoc}
986
     */
987 34
    public function next()
988
    {
989 34
        return next($this->items);
990
    }
991
992
    /**
993
     * {@inheritDoc}
994
     *
995
     * @todo Should this return $this?
996
     */
997 93
    public function rewind()
998
    {
999 93
        reset($this->items);
1000 93
    }
1001
1002
    /**
1003
     * {@inheritDoc}
1004
     */
1005 36
    public function valid()
1006
    {
1007 36
        return $this->has(key($this->items));
1008
    }
1009
1010
    /** ++++                  ++++ **/
1011
    /** ++   Countable Method   ++ **/
1012
    /** ++++                  ++++ **/
1013
1014
    /**
1015
     * {@inheritDoc}
1016
     */
1017 10
    public function count()
1018
    {
1019 10
        return count($this->items);
1020
    }
1021
}