SliceIterator::offsetGet()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php namespace Mbh\Iterator;
2
3
/**
4
 * MBHFramework
5
 *
6
 * @link      https://github.com/MBHFramework/mbh-framework
7
 * @copyright Copyright (c) 2017 Ulises Jeremias Cornejo Fandos
8
 * @license   https://github.com/MBHFramework/mbh-framework/blob/master/LICENSE (MIT License)
9
 */
10
11
use ArrayAccess;
12
use LimitIterator;
13
use JsonSerializable;
14
use Countable;
15
use Iterator;
16
use InvalidArgumentException;
17
use RuntimeException;
18
19
/**
20
* Iterator to allow a slice to be used like an array
21
*/
22
23
class SliceIterator extends LimitIterator implements ArrayAccess, Countable, JsonSerializable
24
{
25
    protected $count = 0;
26
    protected $begin = 0;
27
28
    const INVALID_INDEX = 'Index invalid or out of range';
29
30
    /**
31
     * Build an iterator over a slice of an ArrayAccess object
32
     * Unlike a LimitIterator, the $end defines the last index, not the count
33
     *
34
     * @param Iterator $iterator An ArrayAccess iterator, e.g. SplFixedArray
35
     * @param int $begin The starting offset of the slice
36
     * @param int $end The last index of the slice
37
     */
38
    public function __construct(Iterator $iterator, $begin = 0, $end = null)
39
    {
40
        if (!(
41
            $iterator instanceof ArrayAccess
42
          && $iterator instanceof Countable
43
        )) {
44
            throw new InvalidArgumentException('Iterator must be a Countable ArrayAccess');
45
        }
46
47
        $count = count($iterator);
48
49
        // Negative begin means start from the end
50
        if ($begin < 0) {
51
            $begin = max(0, $count + $begin);
52
        }
53
54
        // If no end set, assume whole array
55
        if ($end === null) {
56
            $end = $count;
57
        } elseif ($end < 0) {
58
            // Ends counting back from start
59
            $end = max($begin, $count + $end);
60
        }
61
62
        // Set the size of iterable object, for quick-lookup
63
        $this->count = max(0, $end - $begin);
64
65
        // Need to store the starting offset to adjust by
66
        $this->begin = $begin;
67
68
        // Init as LimitIterator
69
        parent::__construct($iterator, $this->begin, $this->count);
70
    }
71
72
    /**
73
     * Rewind, extended for clean results on empty sets
74
     */
75
    public function rewind()
76
    {
77
        // no need to rewind on empty sets
78
        if ($this->count > 0) {
79
            parent::rewind();
80
        }
81
    }
82
83
    /**
84
     * Countable
85
     */
86
    public function count(): int
87
    {
88
        return $this->count;
89
    }
90
91
    /**
92
     * ArrayAccess
93
     */
94
    public function offsetExists($offset)
95
    {
96
        return $offset >= 0 && $offset < $this->count;
97
    }
98
99
    public function offsetGet($offset)
100
    {
101
        if ($this->offsetExists($offset)) {
102
            return iterator_to_array($this)->offsetGet($offset + $this->begin);
103
        } else {
104
            throw new RuntimeException(self::INVALID_INDEX);
105
        }
106
    }
107
108
    public function offsetSet($offset, $value)
109
    {
110
        return iterator_to_array($this)->offsetSet($offset + $this->begin, $value);
111
    }
112
113
    public function offsetUnset($offset)
114
    {
115
        return iterator_to_array($this)->offsetUnset($offset + $this->begin);
116
    }
117
118
    /**
119
     * JsonSerializable
120
     */
121
    public function jsonSerialize()
122
    {
123
        return $this->toArray();
124
    }
125
126
    public function toArray()
127
    {
128
        return iterator_to_array($this, false);
129
    }
130
}
131