Skip to content
This repository was archived by the owner on Feb 17, 2025. It is now read-only.

Commit 57509b5

Browse files
committed
Add support for locking proxies and never discard them
1 parent d764444 commit 57509b5

File tree

4 files changed

+69
-6
lines changed

4 files changed

+69
-6
lines changed

infection.json.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"ReactParallel\\ObjectProxy\\Proxy::__destruct::109",
3636
"ReactParallel\\ObjectProxy\\NonExistentInterface::interface::22",
3737
"ReactParallel\\ObjectProxy\\Message\\Parcel::notify::27",
38-
"ReactParallel\\ObjectProxy\\Proxy\\Instance::interface::36"
38+
"ReactParallel\\ObjectProxy\\Proxy\\Instance::interface::39"
3939
]
4040
}
4141
}

src/Proxy.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function has(string $interface): bool
8989
return array_key_exists($interface, self::KNOWN_INTERFACE);
9090
}
9191

92-
public function create(object $object, string $interface): object
92+
public function create(object $object, string $interface, bool $locked = false): object
9393
{
9494
if ($this->has($interface) === self::HASNT_PROXYABLE_INTERFACE) {
9595
throw NonExistentInterface::create($interface);
@@ -99,7 +99,7 @@ public function create(object $object, string $interface): object
9999
* @psalm-suppress EmptyArrayAccess
100100
*/
101101
$class = self::KNOWN_INTERFACE[$interface];
102-
$instance = new Instance($object, $interface);
102+
$instance = new Instance($object, $interface, $locked);
103103
$hash = $instance->class() . '___' . spl_object_hash($object);
104104

105105
$this->instances[$hash] = $instance;
@@ -212,10 +212,22 @@ private function handleDestruct(Destruct $destruct): void
212212

213213
$instance = $this->instances[$destruct->hash()];
214214
$count = $instance->dereference($destruct->objectHash());
215-
if ($count === 0) {
216-
unset($this->instances[$destruct->hash()]);
215+
216+
$this->countDestruct($instance);
217+
218+
if ($instance->isLocked()) {
219+
return;
217220
}
218221

222+
if ($count !== 0) {
223+
return;
224+
}
225+
226+
unset($this->instances[$destruct->hash()]);
227+
}
228+
229+
private function countDestruct(Instance $instance): void
230+
{
219231
if (! ($this->counterDestruct instanceof Counters)) {
220232
return;
221233
}

src/Proxy/Instance.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ final class Instance
1616
/** @var array<string> */
1717
private array $references = [];
1818

19-
public function __construct(object $object, string $interface)
19+
private bool $locked;
20+
21+
public function __construct(object $object, string $interface, bool $locked)
2022
{
2123
$this->object = $object;
2224
$this->class = get_class($object);
2325
$this->interface = $interface;
26+
$this->locked = $locked;
2427
}
2528

2629
public function object(): object
@@ -49,4 +52,9 @@ public function dereference(string $hash): int
4952

5053
return count($this->references);
5154
}
55+
56+
public function isLocked(): bool
57+
{
58+
return $this->locked;
59+
}
5260
}

tests/ProxyTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,47 @@ public function destructionEdgeCases(): void
207207
);
208208
self::assertSame(1337, $leet);
209209
}
210+
211+
/**
212+
* @test
213+
*/
214+
public function destructionLocked(): void
215+
{
216+
$loop = EventLoopFactory::create();
217+
$factory = new Factory($loop);
218+
$registry = new InMemmoryRegistry();
219+
$proxy = (new Proxy($factory))->withMetrics($registry);
220+
$limitedPool = $factory->limitedPool(13);
221+
$registryProxy = $proxy->create($registry, Registry::class, true);
222+
$fn = static function (int $int, WyriHaximus__Metrics_RegistryProxy $registryProxy, int $sleep): int {
223+
sleep($sleep);
224+
$registryProxy->counter('counter', 'bla bla bla', new Label\Name('name'))->counter(new Label('name', 'value'))->incr();
225+
226+
return $int;
227+
};
228+
229+
$promises = [];
230+
foreach (range(0, 3) as $i) {
231+
$promises[] = $limitedPool->run($fn, [$i, $registryProxy, 0]);
232+
}
233+
234+
$leet = $this->await(
235+
// @phpstan-ignore-next-line
236+
all($promises)->then(static function (array $v) use ($factory): PromiseInterface {
237+
return new Promise(static function (callable $resolve) use ($v, $factory): void {
238+
$factory->loop()->addTimer(3, static function () use ($resolve, $v): void {
239+
$resolve($v);
240+
});
241+
});
242+
})->then(static function () use ($fn, $registryProxy, $limitedPool): PromiseInterface {
243+
return $limitedPool->run($fn, [1337, $registryProxy, 20]);
244+
})->always(static function () use ($limitedPool, $loop): void {
245+
$limitedPool->kill();
246+
$loop->stop();
247+
}),
248+
$loop,
249+
133
250+
);
251+
self::assertSame(1337, $leet);
252+
}
210253
}

0 commit comments

Comments
 (0)