Skip to content

Commit

Permalink
Add Interval
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Jul 23, 2024
1 parent 138801f commit 556bb14
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 0 deletions.
98 changes: 98 additions & 0 deletions src/Interval.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php declare(strict_types=1);

namespace Amp;

use Revolt\EventLoop;

/**
* This object invokes the given callback within a new coroutine every $interval seconds until either the
* {@see self::disable()} method is called or the object is destroyed.
*/
final class Interval
{
private readonly string $watcher;

/**
* @param float $interval Invoke the function every $interval seconds.
* @param \Closure():void $closure Use {@see weakClosure()} to avoid a circular reference if storing this object
* as a property of another object.
* @param bool $reference If false, unreference the underlying watcher.
*/
public function __construct(float $interval, \Closure $closure, bool $reference = true)
{
$this->watcher = EventLoop::repeat($interval, $closure);

if (!$reference) {
EventLoop::unreference($this->watcher);
}
}

public function __destruct()
{
EventLoop::cancel($this->watcher);
}

/**
* @return bool True if the internal watcher is referenced.
*/
public function isReferenced(): bool
{
return EventLoop::isReferenced($this->watcher);
}

/**
* References the internal watcher in the event loop, keeping the loop running while the repeat loop is enabled.
*
* @return $this
*/
public function reference(): self
{
EventLoop::reference($this->watcher);

return $this;
}

/**
* Unreferences the internal watcher in the event loop, allowing the loop to stop while the repeat loop is enabled.
*
* @return $this
*/
public function unreference(): self
{
EventLoop::unreference($this->watcher);

return $this;
}

/**
* @return bool True if the repeating timer is enabled.
*/
public function isEnabled(): bool
{
return EventLoop::isEnabled($this->watcher);
}

/**
* Restart the repeating timer if previously stopped with {@see self::disable()}.
*
* @return $this
*/
public function enable(): self
{
EventLoop::enable($this->watcher);

return $this;
}

/**
* Stop the repeating timer. Restart it with {@see self::enable()}.
*
* @return $this
*/
public function disable(): self
{
EventLoop::disable($this->watcher);

return $this;
}
}
49 changes: 49 additions & 0 deletions test/IntervalTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php declare(strict_types=1);

namespace Amp;

class IntervalTest extends TestCase
{
public function testCancelWhenDestroyed(): void
{
$timeout = 0.01;
$invocationCount = 0;
$interval = new Interval($timeout, function () use (&$invocationCount): void {
++$invocationCount;
});

delay($timeout * 1.5);

self::assertGreaterThan(0, $invocationCount);
$originalCount = $invocationCount;

unset($interval);

delay($timeout * 10);

self::assertSame($originalCount, $invocationCount);
}

public function testEnableAndDisable(): void
{
$timeout = 0.01;
$invocationCount = 0;
$interval = new Interval($timeout, function () use (&$invocationCount): void {
++$invocationCount;
});

$interval->disable();
self::assertFalse($interval->isEnabled());

delay($timeout * 2);

self::assertSame(0, $invocationCount);

$interval->enable();
self::assertTrue($interval->isEnabled());

delay($timeout * 1.5);

self::assertSame(1, $invocationCount);
}
}

0 comments on commit 556bb14

Please sign in to comment.