mirror of
https://github.com/danog/amp.git
synced 2024-12-02 17:37:50 +01:00
Rename weaken to weakClosure and limit to closures
This commit is contained in:
parent
d20f07acee
commit
1a2be8f2b2
@ -77,7 +77,7 @@ function delay(float $timeout, bool $reference = true, ?Cancellation $cancellati
|
|||||||
/**
|
/**
|
||||||
* Wait for signal(s) in a non-blocking way.
|
* Wait for signal(s) in a non-blocking way.
|
||||||
*
|
*
|
||||||
* @param int|array $signals Signal number or array of signal numbers.
|
* @param int|int[] $signals Signal number or array of signal numbers.
|
||||||
* @param bool $reference If false, unreference the underlying watcher.
|
* @param bool $reference If false, unreference the underlying watcher.
|
||||||
* @param Cancellation|null $cancellation Cancel waiting if cancellation is requested.
|
* @param Cancellation|null $cancellation Cancel waiting if cancellation is requested.
|
||||||
*
|
*
|
||||||
@ -116,79 +116,55 @@ function trapSignal(int|array $signals, bool $reference = true, ?Cancellation $c
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a callable that maintains a weak reference to any $this object held by the callable.
|
* Returns a Closure that maintains a weak reference to any $this object held by the Closure (a weak-Closure).
|
||||||
* This allows a class to hold a self-referencing callback without creating a circular reference that would
|
* This allows a class to hold a self-referencing Closure without creating a circular reference that would
|
||||||
* prevent or delay automatic garbage collection.
|
* prevent or delay automatic garbage collection.
|
||||||
* Invoking the returned callback after the object is destroyed will throw an instance of Error.
|
* Invoking the returned Closure after the object is destroyed will throw an instance of Error.
|
||||||
*
|
*
|
||||||
* @param callable $callable
|
* @param \Closure $closure
|
||||||
*
|
*
|
||||||
* @return callable
|
* @return \Closure
|
||||||
*/
|
*/
|
||||||
function weaken(callable $callable): callable
|
function weakClosure(\Closure $closure): \Closure
|
||||||
{
|
{
|
||||||
if (!$callable instanceof \Closure) {
|
$reflection = new \ReflectionFunction($closure);
|
||||||
if (\is_string($callable)) {
|
|
||||||
return $callable;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\is_object($callable)) {
|
|
||||||
$callable = [$callable, '__invoke'];
|
|
||||||
}
|
|
||||||
|
|
||||||
[$that, $method] = $callable;
|
|
||||||
if (!\is_object($that)) {
|
|
||||||
return $callable;
|
|
||||||
}
|
|
||||||
|
|
||||||
$reference = \WeakReference::create($that);
|
|
||||||
return static function (mixed ...$args) use ($reference, $method): mixed {
|
|
||||||
$that = $reference->get();
|
|
||||||
if (!$that) {
|
|
||||||
throw new \Error('Weakened callback invoked after referenced object destroyed');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $that->{$method}(...$args);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflection = new \ReflectionFunction($callable);
|
|
||||||
|
|
||||||
$that = $reflection->getClosureThis();
|
$that = $reflection->getClosureThis();
|
||||||
if (!$that) {
|
if (!$that) {
|
||||||
return $callable;
|
return $closure;
|
||||||
}
|
}
|
||||||
|
|
||||||
$method = $reflection->getShortName();
|
$method = $reflection->getShortName();
|
||||||
if ($method !== '{closure}') {
|
if ($method !== '{closure}') {
|
||||||
// Closure from first-class callable or \Closure::fromCallable(), declare an anonymous closure to rebind.
|
// Closure from first-class callable or \Closure::fromCallable(), declare an anonymous closure to rebind.
|
||||||
/** @psalm-suppress InvalidScope Closure is bound before being invoked. */
|
/** @psalm-suppress InvalidScope Closure is bound before being invoked. */
|
||||||
$callable = fn (mixed ...$args) => $this->{$method}(...$args);
|
$closure = fn (mixed ...$args) => $this->{$method}(...$args);
|
||||||
} else {
|
} else {
|
||||||
// Rebind to remove reference to $that
|
// Rebind to remove reference to $that
|
||||||
$callable = $callable->bindTo(new \stdClass());
|
$closure = $closure->bindTo(new \stdClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For internal classes use \Closure::bindTo() without scope.
|
// For internal classes use \Closure::bindTo() without scope.
|
||||||
$useBindTo = !(new \ReflectionClass($that))->isUserDefined();
|
$useBindTo = !(new \ReflectionClass($that))->isUserDefined();
|
||||||
|
|
||||||
$reference = \WeakReference::create($that);
|
$reference = \WeakReference::create($that);
|
||||||
return static function (mixed ...$args) use ($reference, $callable, $useBindTo): mixed {
|
|
||||||
|
return static function (mixed ...$args) use ($reference, $closure, $useBindTo): mixed {
|
||||||
$that = $reference->get();
|
$that = $reference->get();
|
||||||
if (!$that) {
|
if (!$that) {
|
||||||
throw new \Error('Weakened callback invoked after referenced object destroyed');
|
throw new \Error('Weakened closure invoked after referenced object destroyed');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($useBindTo) {
|
if ($useBindTo) {
|
||||||
$callable = $callable->bindTo($that);
|
$closure = $closure->bindTo($that);
|
||||||
|
|
||||||
if (!$callable) {
|
if (!$closure) {
|
||||||
throw new \RuntimeException('Unable to rebind function to object of type ' . \get_class($that));
|
throw new \RuntimeException('Unable to rebind function to object of type ' . \get_class($that));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $callable(...$args);
|
return $closure(...$args);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $callable->call($that, ...$args);
|
return $closure->call($that, ...$args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ namespace Amp;
|
|||||||
use Amp\PHPUnit\AsyncTestCase;
|
use Amp\PHPUnit\AsyncTestCase;
|
||||||
use Revolt\EventLoop;
|
use Revolt\EventLoop;
|
||||||
|
|
||||||
class WeakenTest extends AsyncTestCase
|
class WeakClosureTest extends AsyncTestCase
|
||||||
{
|
{
|
||||||
public function provideObjectFactories(): iterable
|
public function provideObjectFactories(): iterable
|
||||||
{
|
{
|
||||||
@ -17,7 +17,7 @@ class WeakenTest extends AsyncTestCase
|
|||||||
{
|
{
|
||||||
$this->callbackId = $id = EventLoop::repeat(
|
$this->callbackId = $id = EventLoop::repeat(
|
||||||
0.001,
|
0.001,
|
||||||
weaken(function (string $callbackId) use (&$count): void {
|
weakClosure(function (string $callbackId) use (&$count): void {
|
||||||
AsyncTestCase::assertNotNull($this);
|
AsyncTestCase::assertNotNull($this);
|
||||||
AsyncTestCase::assertStringContainsString('anonymous', \get_class($this));
|
AsyncTestCase::assertStringContainsString('anonymous', \get_class($this));
|
||||||
AsyncTestCase::assertSame($callbackId, $this->callbackId);
|
AsyncTestCase::assertSame($callbackId, $this->callbackId);
|
||||||
@ -40,7 +40,7 @@ class WeakenTest extends AsyncTestCase
|
|||||||
public function __construct(int &$count, &$id)
|
public function __construct(int &$count, &$id)
|
||||||
{
|
{
|
||||||
$callbackIdRef = &$this->callbackId;
|
$callbackIdRef = &$this->callbackId;
|
||||||
$this->callbackId = $id = EventLoop::repeat(0.001, weaken(static function (string $callbackId) use (
|
$this->callbackId = $id = EventLoop::repeat(0.001, weakClosure(static function (string $callbackId) use (
|
||||||
&$count,
|
&$count,
|
||||||
&$callbackIdRef
|
&$callbackIdRef
|
||||||
): void {
|
): void {
|
||||||
@ -66,7 +66,7 @@ class WeakenTest extends AsyncTestCase
|
|||||||
$this->count = &$count;
|
$this->count = &$count;
|
||||||
$this->callbackId = $id = EventLoop::repeat(
|
$this->callbackId = $id = EventLoop::repeat(
|
||||||
0.001,
|
0.001,
|
||||||
weaken(\Closure::fromCallable([$this, 'callback']))
|
weakClosure(\Closure::fromCallable([$this, 'callback']))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ class WeakenTest extends AsyncTestCase
|
|||||||
public function __construct(int &$count, &$id)
|
public function __construct(int &$count, &$id)
|
||||||
{
|
{
|
||||||
$this->count = &$count;
|
$this->count = &$count;
|
||||||
$this->callbackId = $id = EventLoop::repeat(0.001, weaken($this));
|
$this->callbackId = $id = EventLoop::repeat(0.001, weakClosure(\Closure::fromCallable($this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(string $callbackId): void
|
public function __invoke(string $callbackId): void
|
Loading…
Reference in New Issue
Block a user