Skip to content

Commit c02b303

Browse files
authored
chore: Refactor optimization for internal callables (#289)
1 parent 9c0bb53 commit c02b303

File tree

3 files changed

+29
-35
lines changed

3 files changed

+29
-35
lines changed

src/Standard.php

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,13 +1563,7 @@ public function tap(callable $func): self
15631563
private static function tapValues(iterable $previous, callable $func): Generator
15641564
{
15651565
foreach ($previous as $key => $value) {
1566-
try {
1567-
$func($value, $key);
1568-
} catch (ArgumentCountError) {
1569-
// Optimization to reduce the number of argument count errors when calling internal callables.
1570-
$func = self::wrapInternalCallable($func);
1571-
$func($value);
1572-
}
1566+
self::callWithValueKey($func, $value, $key);
15731567

15741568
yield $key => $value;
15751569
}
@@ -1602,16 +1596,24 @@ private function eachInternal(callable $func): void
16021596
}
16031597

16041598
foreach ($this->pipeline as $key => $value) {
1605-
try {
1606-
$func($value, $key);
1607-
} catch (ArgumentCountError) {
1608-
// Optimization to reduce the number of argument count errors when calling internal callables.
1609-
// This error is thrown when too many arguments are passed to a built-in function (that are sensitive
1610-
// to extra arguments), so we can wrap it to prevent the errors later. On the other hand, if there
1611-
// are too little arguments passed, it will blow up just a line later.
1612-
$func = self::wrapInternalCallable($func);
1613-
$func($value);
1614-
}
1599+
self::callWithValueKey($func, $value, $key);
1600+
}
1601+
}
1602+
1603+
/**
1604+
* Reference parameter allows wrapped callable to persist across iterations.
1605+
*/
1606+
private static function callWithValueKey(callable &$func, mixed $value, mixed $key): void
1607+
{
1608+
try {
1609+
$func($value, $key);
1610+
} catch (ArgumentCountError) {
1611+
// Optimization to reduce the number of argument count errors when calling internal callables.
1612+
// This error is thrown when too many arguments are passed to a built-in function (that are sensitive
1613+
// to extra arguments), so we can wrap it to prevent the errors later. On the other hand, if there
1614+
// are too little arguments passed, it will blow up just a line later.
1615+
$func = self::wrapInternalCallable($func);
1616+
$func($value);
16151617
}
16161618
}
16171619

tests/EachTest.php

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function testUninitialized(): void
6161
{
6262
$pipeline = new Standard();
6363

64-
$pipeline->each(fn($value) => $this->observeValue($value));
64+
$pipeline->each($this->observeValue(...));
6565

6666
$this->assertSame([], $this->output);
6767
}
@@ -70,7 +70,7 @@ public function testEmpty(): void
7070
{
7171
$pipeline = take([]);
7272

73-
$pipeline->each(fn($value) => $this->observeValue($value));
73+
$pipeline->each($this->observeValue(...));
7474

7575
$this->assertSame([], $this->output);
7676
}
@@ -79,7 +79,7 @@ public function testEmptyGenerator(): void
7979
{
8080
$pipeline = map(static fn() => yield from []);
8181

82-
$pipeline->each(fn($value) => $this->observeValue($value));
82+
$pipeline->each($this->observeValue(...));
8383

8484
$this->assertSame([], $this->output);
8585
}
@@ -88,7 +88,7 @@ public function testNotEmpty(): void
8888
{
8989
$pipeline = take([1, 2, 3, 4]);
9090

91-
$pipeline->each(fn(int $value) => $this->observeValue($value));
91+
$pipeline->each($this->observeValue(...));
9292

9393
$this->assertSame([1, 2, 3, 4], $this->output);
9494
}
@@ -123,9 +123,7 @@ public function testInterrupt(Standard $pipeline): void
123123
});
124124

125125
try {
126-
$pipeline->each(function (int $value): void {
127-
$this->observeValue($value);
128-
});
126+
$pipeline->each($this->observeValue(...));
129127
} catch (LogicException $_) {
130128
$this->assertSame([1, 2], $this->output);
131129
}
@@ -142,13 +140,9 @@ public function testNoDiscard(): void
142140
{
143141
$pipeline = fromArray([1, 2, 3]);
144142

145-
$pipeline->each(function (int $value): void {
146-
$this->observeValue($value);
147-
}, false);
143+
$pipeline->each($this->observeValue(...), false);
148144

149-
$pipeline->each(function (int $value): void {
150-
$this->observeValue($value);
151-
});
145+
$pipeline->each($this->observeValue(...));
152146

153147
$this->assertSame([1, 2, 3, 1, 2, 3], $this->output);
154148
$this->assertSame([], $pipeline->toList());
@@ -206,8 +200,6 @@ public function testCallableReassigned(): void
206200
$pipeline = fromArray(['1', '2', '3']);
207201
$pipeline->each($callback);
208202

209-
$this->assertSame(4, $callback->callCount, 'Expected 1 initial call that throws + 3 successful calls after wrapping');
210-
211203
$this->assertSame([
212204
['1', 0],
213205
['1'],

tests/Fixtures/CallableThrower.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@
2020

2121
use ArgumentCountError;
2222

23+
use function count;
24+
2325
class CallableThrower
2426
{
2527
public array $args = [];
26-
public int $callCount = 0;
2728

2829
public function __invoke(...$args): void
2930
{
3031
$this->args[] = $args;
31-
$this->callCount++;
3232

33-
if (1 === $this->callCount) {
33+
if (count($args) > 1) {
3434
throw new ArgumentCountError();
3535
}
3636
}

0 commit comments

Comments
 (0)