diff --git a/src/Once.php b/src/Once.php index 44f54a8..3f53f13 100644 --- a/src/Once.php +++ b/src/Once.php @@ -24,11 +24,6 @@ final class Once */ private mixed $value; - /** - * @var \Closure(T): bool - */ - private readonly mixed $isAlive; - private bool $isResolved = false; /** @@ -36,18 +31,16 @@ final class Once * @param ?\Closure(T): bool $isAlive */ public function __construct( - private readonly \Closure $function, - ?\Closure $isAlive = null, - ) { - $this->isAlive = $isAlive ?? static fn(): true => true; - } + private \Closure $function, + private readonly ?\Closure $isAlive = null, + ) {} /** * @return T */ public function await(?Cancellation $cancellation = null): mixed { - if ($this->isResolved && ($this->isAlive)($this->value)) { + if ($this->isResolved && ($this->isAlive === null || ($this->isAlive)($this->value))) { return $this->value; } @@ -63,6 +56,10 @@ public function await(?Cancellation $cancellation = null): mixed $this->isResolved = true; + if ($this->isAlive === null) { + $this->function = static fn() => throw new \LogicException('Function has been freed from memory'); + } + return $this->value; } } diff --git a/tests/OnceTest.php b/tests/OnceTest.php index 62d44a7..47190d4 100644 --- a/tests/OnceTest.php +++ b/tests/OnceTest.php @@ -67,4 +67,18 @@ static function (): int { self::assertSame(2, $once->await()); self::assertSame(2, $once->await()); } + + public function testFunctionIsFreedIfIsAliveIsNull(): void + { + $value = new \stdClass(); + $weakValue = \WeakReference::create($value); + $once = new Once(static fn() => $value::class); + unset($value); + + self::assertNotNull($weakValue->get()); + + $once->await(); + + self::assertNull($weakValue->get()); + } }