Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.00% covered (success)
95.00%
19 / 20
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SelectManyIterator
95.00% covered (success)
95.00%
19 / 20
83.33% covered (warning)
83.33%
5 / 6
13
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 rewind
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 key
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 current
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 next
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 valid
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\Collection;
6
7use EmptyIterator;
8use Iterator;
9use PeServer\Core\Collection\TraverseUtility;
10use PeServer\Core\Throws\CallbackTypeError;
11
12/**
13 * selectMany イテレータ。
14 *
15 * @template TKey of array-key
16 * @template TValue
17 * @template TResult
18 * @implements Iterator<TKey,TResult>
19 */
20class SelectManyIterator implements Iterator
21{
22    #region variable
23
24    /** @phpstan-var Iterator<TKey,Iterator<TKey,TValue>> */
25    private Iterator $outerIterator;
26    /** @phpstan-var Iterator<TKey,TValue> */
27    private Iterator $innerIterator;
28
29    #endregion
30
31    /**
32     * 生成。
33     *
34     * @param Iterator $iterator
35     * @phpstan-param Iterator<TKey,Iterator<TKey,TValue>> $iterator
36     * @param mixed $callback
37     * @phpstan-param callable(TValue,TKey):(TResult) $callback
38     */
39    public function __construct(
40        Iterator $iterator,
41        private mixed $callback
42    ) {
43        if (!is_callable($callback)) { //@phpstan-ignore-line phpstan-param callable
44            throw new CallbackTypeError('$callback');
45        }
46
47        $this->outerIterator = $iterator;
48        $this->innerIterator = new EmptyIterator();
49    }
50
51    #region Iterator
52
53    public function rewind(): void
54    {
55        $this->outerIterator->rewind();
56        if ($this->outerIterator->valid()) {
57            $this->innerIterator = TraverseUtility::toIterator($this->outerIterator->current());
58        }
59    }
60
61    /**
62     * @return int
63     */
64    public function key(): mixed
65    {
66        return $this->innerIterator->key();
67    }
68
69    /**
70     * @phpstan-return TResult
71     */
72    public function current(): mixed
73    {
74        return call_user_func($this->callback, $this->innerIterator->current(), $this->innerIterator->key());
75    }
76
77    public function next(): void
78    {
79        if ($this->innerIterator->valid()) {
80            $this->innerIterator->next();
81            if ($this->innerIterator->valid()) {
82                return;
83            }
84        }
85
86        if ($this->outerIterator->valid()) {
87            $this->outerIterator->next();
88            if ($this->outerIterator->valid()) {
89                $this->innerIterator = TraverseUtility::toIterator($this->outerIterator->current());
90            }
91        }
92    }
93
94    public function valid(): bool
95    {
96        if ($this->innerIterator->valid()) {
97            return true;
98        }
99
100        return $this->outerIterator->valid();
101    }
102
103    #endregion
104}