Skip to content

Commit 637556b

Browse files
committed
Change how to stringify Iterator objects
I'm changing the notation to ensure we keep consistency with the recent changes, so I'm using "{}" to represent the body and "current()" to make it explicit that it's a method call. I changed the behavior of this stringifier. After all, it might be unwanted to iterate over the whole object to stringify it because it might do an expensive operation. Signed-off-by: Henrique Moody <[email protected]>
1 parent e33bb7c commit 637556b

File tree

8 files changed

+124
-117
lines changed

8 files changed

+124
-117
lines changed

src/Stringifiers/ClusterStringifier.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public static function createDefault(): self
4141
$jsonParsableStringifier = new JsonParsableStringifier();
4242

4343
$stringifier->setStringifiers([
44-
new TraversableStringifier($stringifier, $quoter),
44+
new IteratorObjectStringifier($stringifier, $quoter),
4545
new DateTimeStringifier($quoter, DateTimeInterface::ATOM),
4646
new ThrowableStringifier($stringifier, $quoter),
4747
new StringableObjectStringifier($jsonParsableStringifier, $quoter),

src/Stringifiers/TraversableStringifier.php renamed to src/Stringifiers/IteratorObjectStringifier.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,13 @@
1010

1111
namespace Respect\Stringifier\Stringifiers;
1212

13+
use Iterator;
1314
use Respect\Stringifier\Quoter;
1415
use Respect\Stringifier\Stringifier;
15-
use Traversable;
1616

17-
use function iterator_to_array;
1817
use function sprintf;
1918

20-
final class TraversableStringifier implements Stringifier
19+
final class IteratorObjectStringifier implements Stringifier
2120
{
2221
public function __construct(
2322
private readonly Stringifier $stringifier,
@@ -27,15 +26,15 @@ public function __construct(
2726

2827
public function stringify(mixed $raw, int $depth): ?string
2928
{
30-
if (!$raw instanceof Traversable) {
29+
if (!$raw instanceof Iterator) {
3130
return null;
3231
}
3332

3433
return $this->quoter->quote(
3534
sprintf(
36-
'[traversable] (%s: %s)',
35+
'%s { current() => %s }',
3736
$raw::class,
38-
$this->stringifier->stringify(iterator_to_array($raw), $depth + 1)
37+
$this->stringifier->stringify($raw->current(), $depth + 1)
3938
),
4039
$depth
4140
);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* This file is part of Respect/Stringifier.
5+
* Copyright (c) Henrique Moody <[email protected]>
6+
* SPDX-License-Identifier: MIT
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
/**
12+
* @implements Iterator<int>
13+
*/
14+
final class ConcreteIterator implements Iterator
15+
{
16+
private const VALUES = [1, 2, 3];
17+
18+
private int $position = 0;
19+
20+
public function current(): int
21+
{
22+
return self::VALUES[$this->position];
23+
}
24+
25+
public function next(): void
26+
{
27+
$this->position++;
28+
}
29+
30+
public function key(): int
31+
{
32+
return $this->position;
33+
}
34+
35+
public function valid(): bool
36+
{
37+
return array_key_exists($this->position, self::VALUES);
38+
}
39+
40+
public function rewind(): void
41+
{
42+
$this->position = 0;
43+
}
44+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--FILE--
2+
<?php
3+
4+
declare(strict_types=1);
5+
6+
require 'vendor/autoload.php';
7+
8+
outputMultiple(
9+
new ConcreteIterator(),
10+
new ArrayIterator([4, 5, 6]),
11+
(static fn(int $number) => yield $number)(7),
12+
);
13+
?>
14+
--EXPECT--
15+
`ConcreteIterator { current() => 1 }`
16+
`ArrayIterator { current() => 4 }`
17+
`Generator { current() => 7 }`

tests/integration/stringify-object-traversable.phpt

Lines changed: 0 additions & 11 deletions
This file was deleted.

tests/src/MyTraversable.php

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/*
4+
* This file is part of Respect/Stringifier.
5+
* Copyright (c) Henrique Moody <[email protected]>
6+
* SPDX-License-Identifier: MIT
7+
*/
8+
9+
declare(strict_types=1);
10+
11+
namespace Respect\Stringifier\Test\Unit\Stringifiers;
12+
13+
use ConcreteIterator;
14+
use PHPUnit\Framework\Attributes\CoversClass;
15+
use PHPUnit\Framework\Attributes\Test;
16+
use PHPUnit\Framework\TestCase;
17+
use Respect\Stringifier\Stringifiers\IteratorObjectStringifier;
18+
use Respect\Stringifier\Test\Double\FakeQuoter;
19+
use Respect\Stringifier\Test\Double\FakeStringifier;
20+
21+
use function sprintf;
22+
23+
#[CoversClass(IteratorObjectStringifier::class)]
24+
final class IteratorObjectStringifierTest extends TestCase
25+
{
26+
private const DEPTH = 0;
27+
28+
#[Test]
29+
public function itShouldNotStringifyRawValueWhenItIsNotTraversable(): void
30+
{
31+
$sut = new IteratorObjectStringifier(new FakeStringifier(), new FakeQuoter());
32+
33+
self::assertNull($sut->stringify([1, 2, 3, 4], self::DEPTH));
34+
}
35+
36+
#[Test]
37+
public function itShouldStringifyRawValueWhenItIsAnInstanceOfIterator(): void
38+
{
39+
$raw = new ConcreteIterator();
40+
41+
$stringifier = new FakeStringifier();
42+
$quoter = new FakeQuoter();
43+
44+
$sut = new IteratorObjectStringifier($stringifier, $quoter);
45+
46+
$actual = $sut->stringify($raw, self::DEPTH);
47+
$expected = $quoter->quote(
48+
sprintf(
49+
'ConcreteIterator { current() => %s }',
50+
$stringifier->stringify($raw->current(), self::DEPTH + 1),
51+
),
52+
self::DEPTH
53+
);
54+
55+
self::assertSame($expected, $actual);
56+
}
57+
}

tests/unit/Stringifiers/TraversableStringifierTest.php

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)