Passed
Push — 1.x ( 3a457a...b78ae7 )
by Ulises Jeremias
02:31
created

ConcatIterator::offsetUnset()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 1
b 0
f 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 AppendIterator;
13
use JsonSerializable;
14
use Countable;
15
use Iterator;
16
use RuntimeException;
17
use InvalidArgumentException;
18
19
/**
20
 * Iterator to allow multiple iterators to be concatenated
21
 */
22
23
class ConcatIterator extends AppendIterator implements Countable, Iterator
24
{
25
    const INVALID_INDEX = 'Index invalid or out of range';
26
27
    /** @var int $count Fast-lookup count for full set of iterators */
28
    public $count = 0;
29
30
    /**
31
     * Build an iterator over multiple iterators
32
     * Unlike a LimitIterator, the $end defines the last index, not the count
33
     *
34
     * @param Iterator $iterator,... Concat iterators in order
35
     */
36
    public function __construct(...$args)
37
    {
38
        parent::__construct();
39
        foreach ($args as $i => $iterator) {
40
            if (
41
                $iterator instanceof ArrayAccess &&
42
                $iterator instanceof Countable
43
            ) {
44
                // Unroll other ConcatIterators, so we avoid deep iterator stacks
45
                if ($iterator instanceof self) {
46
                    foreach ($iterator->getArrayIterator() as $innerIt) {
0 ignored issues
show
Bug introduced by
The method getArrayIterator() does not exist on Countable. It seems like you code against a sub-type of Countable such as Mbh\Iterator\ConcatIterator. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
                    foreach ($iterator->/** @scrutinizer ignore-call */ getArrayIterator() as $innerIt) {
Loading history...
Bug introduced by
The method getArrayIterator() does not exist on ArrayAccess. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

46
                    foreach ($iterator->/** @scrutinizer ignore-call */ getArrayIterator() as $innerIt) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
47
                        $this->append($innerIt);
48
                    }
49
                } else {
50
                    $this->append($iterator);
0 ignored issues
show
Bug introduced by
$iterator of type ArrayAccess&Countable is incompatible with the type Iterator expected by parameter $iterator of AppendIterator::append(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

50
                    $this->append(/** @scrutinizer ignore-type */ $iterator);
Loading history...
51
                }
52
53
                $this->count += count($iterator);
54
            } else {
55
                throw new InvalidArgumentException(
56
                    'Argument ' . $i .
57
                    ' passed to ' . __METHOD__ .
58
                    ' must be of type ArrayAccess, Countable, and Traversable. ' .
59
                    gettype($iterator) . ' given.'
60
                );
61
            }
62
        }
63
    }
64
65
    /**
66
     * Countable
67
     */
68
    public function count(): int
69
    {
70
        return $this->count;
71
    }
72
73
    public function toArray(): array
74
    {
75
        return iterator_to_array($this, false);
76
    }
77
78
    /**
79
     * Find which of the inner iterators an index corresponds to
80
     *
81
     * @param int $index
82
     * @return [ArrayAccess, int] The iterator and interior index
83
     */
0 ignored issues
show
Documentation Bug introduced by
The doc comment [ArrayAccess, int] at position 0 could not be parsed: Unknown type name '[' at position 0 in [ArrayAccess, int].
Loading history...
84
    protected function getIteratorByIndex($index = 0)
85
    {
86
        $runningCount = 0;
87
        foreach ($this->getArrayIterator() as $innerIt) {
88
            $count = count($innerIt);
89
            if ($index < $runningCount + $count) {
90
                return [$innerIt, $index - $runningCount];
91
            }
92
            $runningCount += $count;
93
        }
94
95
        return null;
96
    }
97
}
98