Skip to content

Commit 9e87d6b

Browse files
author
Thomas Vargiu
committed
Hotfix memory leak recreating new chain instances
1 parent 03086a2 commit 9e87d6b

File tree

2 files changed

+61
-22
lines changed

2 files changed

+61
-22
lines changed

src/PluginChain.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Http\Client\Common;
6+
7+
use Http\Client\Common\Exception\LoopException;
8+
use Http\Promise\Promise;
9+
use Psr\Http\Message\RequestInterface;
10+
11+
final class PluginChain
12+
{
13+
/** @var Plugin[] */
14+
private $plugins;
15+
16+
/** @var callable */
17+
private $clientCallable;
18+
19+
/** @var int */
20+
private $maxRestarts;
21+
22+
/** @var int */
23+
private $restarts = 0;
24+
25+
/**
26+
* @param Plugin[] $plugins
27+
* @param callable $clientCallable
28+
* @param int $maxRestarts
29+
*/
30+
public function __construct(array $plugins, callable $clientCallable, int $maxRestarts)
31+
{
32+
$this->plugins = $plugins;
33+
$this->clientCallable = $clientCallable;
34+
$this->maxRestarts = $maxRestarts;
35+
}
36+
37+
private function createChain(): callable
38+
{
39+
$lastCallable = $this->clientCallable;
40+
41+
foreach ($this->plugins as $plugin) {
42+
$lastCallable = function (RequestInterface $request) use ($plugin, $lastCallable) {
43+
return $plugin->handleRequest($request, $lastCallable, $this);
44+
};
45+
}
46+
47+
return $lastCallable;
48+
}
49+
50+
public function __invoke(RequestInterface $request): Promise
51+
{
52+
if ($this->restarts > $this->maxRestarts) {
53+
throw new LoopException('Too many restarts in plugin client', $request);
54+
}
55+
56+
++$this->restarts;
57+
58+
return $this->createChain()($request);
59+
}
60+
}

src/PluginClient.php

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -125,27 +125,6 @@ private function configure(array $options = []): array
125125
*/
126126
private function createPluginChain(array $pluginList, callable $clientCallable): callable
127127
{
128-
$firstCallable = $lastCallable = $clientCallable;
129-
130-
while ($plugin = array_pop($pluginList)) {
131-
$lastCallable = function (RequestInterface $request) use ($plugin, $lastCallable, &$firstCallable) {
132-
return $plugin->handleRequest($request, $lastCallable, $firstCallable);
133-
};
134-
135-
$firstCallable = $lastCallable;
136-
}
137-
138-
$firstCalls = 0;
139-
$firstCallable = function (RequestInterface $request) use ($lastCallable, &$firstCalls) {
140-
if ($firstCalls > $this->options['max_restarts']) {
141-
throw new LoopException('Too many restarts in plugin client', $request);
142-
}
143-
144-
++$firstCalls;
145-
146-
return $lastCallable($request);
147-
};
148-
149-
return $firstCallable;
128+
return new PluginChain($pluginList, $clientCallable, $this->options['max_restarts']);
150129
}
151130
}

0 commit comments

Comments
 (0)