Skip to content

Commit 7c99ea1

Browse files
committedDec 16, 2021
feat: Add ClosureIteratorAggregate and IterableIteratorAggregate.
1 parent 3077769 commit 7c99ea1

5 files changed

+231
-0
lines changed
 

‎README.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ The missing PHP iterators.
1919
2 Iterators:
2020

2121
* `ClosureIterator`: ClosureIterator(callable $callable, array $arguments = [])
22+
* `ClosureIteratorAggregate`: ClosureIteratorAggregate(callable $callable, array $arguments = [])
2223
* `IterableIterator`: IterableIterator(iterable $iterable)
24+
* `IterableIteratorAggregate`: IterableIterator(iterable $iterable)
2325

2426
## Installation
2527

‎src/ClosureIteratorAggregate.php

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/**
4+
* For the full copyright and license information, please view
5+
* the LICENSE file that was distributed with this source code.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace loophp\iterators;
11+
12+
use IteratorAggregate;
13+
use Traversable;
14+
15+
/**
16+
* @template TKey
17+
* @template T
18+
*
19+
* @implements IteratorAggregate<TKey, T>
20+
*/
21+
final class ClosureIteratorAggregate implements IteratorAggregate
22+
{
23+
/**
24+
* @var callable(mixed ...$parameters): iterable<TKey, T>
25+
*/
26+
private $callable;
27+
28+
/**
29+
* @var iterable<int, mixed>
30+
*/
31+
private iterable $parameters;
32+
33+
/**
34+
* @param callable(mixed ...$parameters): iterable<TKey, T> $callable
35+
* @param iterable<int, mixed> $parameters
36+
*/
37+
public function __construct(callable $callable, iterable $parameters = [])
38+
{
39+
$this->callable = $callable;
40+
$this->parameters = $parameters;
41+
}
42+
43+
public function getIterator(): Traversable
44+
{
45+
return yield from ($this->callable)(...$this->parameters);
46+
}
47+
}

‎src/IterableIteratorAggregate.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/**
4+
* For the full copyright and license information, please view
5+
* the LICENSE file that was distributed with this source code.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace loophp\iterators;
11+
12+
use IteratorAggregate;
13+
use Traversable;
14+
15+
/**
16+
* @template TKey
17+
* @template T
18+
*
19+
* @implements IteratorAggregate<TKey, T>
20+
*/
21+
final class IterableIteratorAggregate implements IteratorAggregate
22+
{
23+
/**
24+
* @var IteratorAggregate<TKey, T>
25+
*/
26+
private IteratorAggregate $iterator;
27+
28+
/**
29+
* @param iterable<TKey, T> $iterable
30+
*/
31+
public function __construct(iterable $iterable)
32+
{
33+
$this->iterator = new ClosureIteratorAggregate(static fn () => yield from $iterable);
34+
}
35+
36+
public function getIterator(): Traversable
37+
{
38+
return $this->iterator->getIterator();
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/**
4+
* For the full copyright and license information, please view
5+
* the LICENSE file that was distributed with this source code.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace tests\loophp\iterators;
11+
12+
use loophp\iterators\ClosureIteratorAggregate;
13+
use PHPUnit\Framework\TestCase;
14+
15+
/**
16+
* @internal
17+
* @coversDefaultClass \loophp\iterators
18+
*/
19+
final class ClosureIteratorAggregateTest extends TestCase
20+
{
21+
private const LIST_DATA = [1, 2, 3];
22+
23+
private const MAP_DATA = ['foo' => 1, 'bar' => 2];
24+
25+
public function testInitializeFromCallableWithArray(): void
26+
{
27+
$iterator = new ClosureIteratorAggregate(
28+
static fn (array $iterable): array => $iterable,
29+
[self::LIST_DATA]
30+
);
31+
32+
self::assertTrue($iterator->getIterator()->valid());
33+
34+
self::assertEquals(
35+
self::LIST_DATA,
36+
iterator_to_array($iterator->getIterator())
37+
);
38+
}
39+
40+
public function testRewind(): void
41+
{
42+
$iterator = new ClosureIteratorAggregate(
43+
static fn (array $iterable): array => $iterable,
44+
[self::MAP_DATA]
45+
);
46+
$newIterator = $iterator->getIterator();
47+
48+
self::assertEquals(1, $newIterator->current());
49+
$newIterator->next();
50+
self::assertEquals(2, $newIterator->current());
51+
52+
$newIterator = $iterator->getIterator();
53+
54+
self::assertEquals(1, $newIterator->current());
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/**
4+
* For the full copyright and license information, please view
5+
* the LICENSE file that was distributed with this source code.
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace tests\loophp\iterators;
11+
12+
use ArrayIterator;
13+
use Generator;
14+
use loophp\iterators\IterableIteratorAggregate;
15+
use PHPUnit\Framework\TestCase;
16+
17+
/**
18+
* @internal
19+
* @coversDefaultClass \loophp\iterators
20+
*/
21+
final class IterableIteratorAggregateTest extends TestCase
22+
{
23+
public function testGetAnIntKey(): void
24+
{
25+
$iterator = (new IterableIteratorAggregate(range(1, 5)))->getIterator();
26+
27+
self::assertEquals(0, $iterator->key());
28+
$iterator->next();
29+
self::assertEquals(1, $iterator->key());
30+
}
31+
32+
public function testGetAStringKey(): void
33+
{
34+
$iterator = (new IterableIteratorAggregate(['foo' => 1, 'bar' => 2]))->getIterator();
35+
self::assertEquals('foo', $iterator->key());
36+
$iterator->next();
37+
self::assertEquals('bar', $iterator->key());
38+
}
39+
40+
public function testIsInitializableFromArray(): void
41+
{
42+
$iterator = (new IterableIteratorAggregate(['foo', 'bar', 'baz']))->getIterator();
43+
44+
self::assertEquals('foo', $iterator->current());
45+
}
46+
47+
public function testIsInitializableFromGenerator(): void
48+
{
49+
$gen = static fn (): Generator => yield from ['foo', 'bar', 'baz'];
50+
51+
$iterator = (new IterableIteratorAggregate($gen()))->getIterator();
52+
53+
self::assertEquals('foo', $iterator->current());
54+
}
55+
56+
public function testIsInitializableFromIterator(): void
57+
{
58+
$iterator = (new IterableIteratorAggregate(new ArrayIterator(['foo', 'bar', 'baz'])))->getIterator();
59+
60+
self::assertEquals('foo', $iterator->current());
61+
}
62+
63+
public function testRenewGenerator(): void
64+
{
65+
$iia = new IterableIteratorAggregate(['foo']);
66+
$iterator = $iia->getIterator();
67+
68+
self::assertEquals('foo', $iterator->current());
69+
$iterator->next();
70+
self::assertNull($iterator->current());
71+
72+
// Iterator renewal here (instead of using rewind)
73+
$iterator = $iia->getIterator();
74+
75+
self::assertEquals('foo', $iterator->current());
76+
}
77+
78+
public function testUseNext(): void
79+
{
80+
$iterator = (new IterableIteratorAggregate(range(1, 5)))->getIterator();
81+
82+
self::assertNull($iterator->next());
83+
84+
self::assertEquals(2, $iterator->current());
85+
}
86+
}

0 commit comments

Comments
 (0)