2020-07-31 15:00:59 +02:00
# Loop
2020-07-21 22:12:34 +02:00
2020-07-23 14:30:56 +02:00
![Build status ](https://github.com/danog/loop/workflows/build/badge.svg )
2020-07-29 23:33:31 +02:00
[![codecov ](https://codecov.io/gh/danog/loop/branch/master/graph/badge.svg )](https://codecov.io/gh/danog/loop)
2020-08-13 16:54:42 +02:00
[![Psalm coverage ](https://shepherd.dev/github/danog/loop/coverage.svg )](https://shepherd.dev/github/vimeo/shepherd)
2020-07-29 23:33:31 +02:00
![License ](https://img.shields.io/badge/license-MIT-blue.svg )
2020-07-21 22:12:34 +02:00
2020-07-24 19:29:14 +02:00
`danog/loop` provides a set of powerful async loop APIs for executing operations periodically or on demand, in background loops a-la threads.
2023-01-22 21:59:13 +01:00
A more flexible and powerful alternative to [AMPHP ](https://amphp.org )'s [repeat ](https://amphp.org/amp/event-loop/api#repeat ) function, allowing dynamically changeable repeat periods and resumes.
2020-07-21 22:12:34 +02:00
## Installation
```bash
composer require danog/loop
```
2020-07-24 19:24:04 +02:00
## API
* Basic
2020-08-18 21:13:18 +02:00
* [GenericLoop ](#genericloop )
* [PeriodicLoop ](#periodicloop )
2020-07-24 19:24:04 +02:00
* Advanced
2020-08-18 21:13:18 +02:00
* [Loop ](#loop )
* [ResumableLoop ](#resumableloop )
2020-07-21 22:12:34 +02:00
All loop APIs are defined by a set of [interfaces ](https://github.com/danog/loop/tree/master/lib/Interfaces ): however, to use them, you would usually have to extend only one of the [abstract class implementations ](https://github.com/danog/loop/tree/master/lib ).
### Loop
2020-07-24 19:28:17 +02:00
[Interface ](https://github.com/danog/loop/blob/master/lib/Interfaces/LoopInterface.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/2.%20Advanced/Loop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
A basic loop, capable of running in background (asynchronously) the code contained in the `loop` function.
2020-07-24 19:24:04 +02:00
API:
2020-07-21 22:12:34 +02:00
```php
2020-07-24 19:24:04 +02:00
namespace danog\Loop;
2020-07-21 22:12:34 +02:00
2020-07-24 19:24:04 +02:00
abstract class Loop
2020-07-21 22:12:34 +02:00
{
2022-12-23 20:45:00 +01:00
abstract public function loop();
2020-07-24 19:24:04 +02:00
abstract public function __toString(): string;
2020-07-21 22:12:34 +02:00
public function start(): bool;
public function isRunning(): bool;
2020-07-24 19:24:04 +02:00
protected function startedLoop(): void;
protected function exitedLoop(): void;
2020-07-21 22:12:34 +02:00
}
```
2020-07-24 19:24:04 +02:00
#### loop()
2022-12-24 19:04:18 +01:00
The `loop` [async fiber ](https://amphp.org/ ) will be run only once, every time the `start` method is called.
2020-07-24 19:24:04 +02:00
#### __toString()
This method should return the loop's name.
2020-08-18 21:13:18 +02:00
It's useful for implementing the [log methods ](#startedloop ).
2020-07-24 19:24:04 +02:00
#### start()
Asynchronously starts the `loop` methods once in background.
2020-07-21 22:12:34 +02:00
Multiple calls to `start` will be ignored, returning `false` instead of `true` .
2020-07-24 19:24:04 +02:00
#### isRunning()
2020-07-21 22:12:34 +02:00
You can use the `isRunning` method to check if the loop is already running.
2020-07-24 19:24:04 +02:00
#### startedLoop()
Optionally, you can override this method to detect and log when the loop is started.
Make sure to always call the parent `startedLoop()` method to avoid issues.
2020-08-18 21:13:18 +02:00
You can use directly `$this` as loop name when logging, thanks to the custom [__toString ](#__tostring ) method.
2020-07-24 19:24:04 +02:00
#### exitedLoop()
Optionally, you can override this method to detect and log when the loop is ended.
Make sure to always call the parent `exitedLoop()` method to avoid issues.
2020-08-18 21:13:18 +02:00
You can use directly `$this` as loop name when logging, thanks to the custom [__toString ](#__tostring ) method.
2020-07-21 22:12:34 +02:00
### ResumableLoop
2020-07-24 19:28:17 +02:00
[Interface ](https://github.com/danog/loop/blob/master/lib/Interfaces/ResumableLoopInterface.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/2.%20Advanced/ResumableLoop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
A way more useful loop that exposes APIs to pause and resume the execution of the loop, both from outside of the loop, and in a cron-like manner from inside of the loop.
```php
namespace danog\Loop;
2020-07-24 19:24:04 +02:00
abstract class ResumableLoop extends Loop
2020-07-21 22:12:34 +02:00
{
2022-12-24 14:36:39 +01:00
public function pause(?int $time = null): Future;
public function resume(): Future;
2020-07-21 22:12:34 +02:00
}
```
2020-07-24 19:24:04 +02:00
All methods from [Loop ](#loop ), plus:
#### pause()
Pauses the loop for the specified number of milliseconds, or forever if `null` is provided.
#### resume()
Forcefully resume the loop from the outside.
2022-12-24 19:04:18 +01:00
Returns a future that is resolved when the loop is paused again.
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
### GenericLoop
2020-07-24 19:28:17 +02:00
[Class ](https://github.com/danog/loop/blob/master/lib/Generic/GenericLoop.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/1.%20Basic/GenericLoop.php )
2020-07-24 19:24:04 +02:00
2023-01-22 21:59:13 +01:00
If you want a simpler way to use the `ResumableLoop` , you can use the GenericLoop.
2020-07-21 22:12:34 +02:00
```php
2020-07-24 19:24:04 +02:00
namespace danog\Loop\Generic;
2023-01-22 21:59:13 +01:00
class GenericLoop extends ResumableLoop
2020-07-24 19:24:04 +02:00
{
/**
* Stop the loop.
*/
const STOP = -1;
2020-07-21 22:12:34 +02:00
/**
2020-07-24 19:24:04 +02:00
* Pause the loop.
*/
const PAUSE = null;
/**
* Rerun the loop.
*/
const CONTINUE = 0;
/**
* Constructor.
*
* @param callable $callable Callable to run
* @param string $name Loop name
*/
2020-07-24 19:28:17 +02:00
public function __construct(callable $callable, string $name);
2020-07-24 19:24:04 +02:00
/**
* Report pause, can be overriden for logging.
2020-07-21 22:12:34 +02:00
*
2020-07-24 19:24:04 +02:00
* @param integer $timeout Pause duration, 0 = forever
*
* @return void
2020-07-21 22:12:34 +02:00
*/
2020-07-24 19:24:04 +02:00
protected function reportPause(int $timeout): void;
/**
* Get loop name, provided to constructor.
*/
public function __toString(): string;
2023-01-22 21:59:13 +01:00
/**
* Stops loop.
*/
public function stop(): void;
2020-07-24 19:24:04 +02:00
}
2020-07-21 22:12:34 +02:00
```
The return value of the callable can be:
* A number - the loop will be paused for the specified number of seconds
* `GenericLoop::STOP` - The loop will stop
* `GenericLoop::PAUSE` - The loop will pause forever (or until the `resume` method is called on the loop object from outside the loop)
* `GenericLoop::CONTINUE` - Return this if you want to rerun the loop without waiting
If the callable does not return anything, the loop will behave is if `GenericLoop::PAUSE` was returned.
### PeriodicLoop
2020-07-24 19:28:17 +02:00
[Class ](https://github.com/danog/loop/blob/master/lib/Generic/PeriodicLoop.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/1.%20Basic/PeriodicLoop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
If you simply want to execute an action every N seconds, [PeriodicLoop ](https://github.com/danog/MadelineProto/blob/master/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php ) is the way to go.
```php
2020-07-24 19:24:04 +02:00
namespace danog\Loop\Generic;
2023-01-22 21:59:13 +01:00
class PeriodicLoop extends ResumableLoop
2020-07-24 19:24:04 +02:00
{
2020-07-21 22:12:34 +02:00
/**
* Constructor.
*
2020-07-24 19:24:04 +02:00
* @param callable $callback Callback to call
* @param string $name Loop name
* @param ?int $interval Loop interval
2020-07-21 22:12:34 +02:00
*/
2020-07-24 19:28:17 +02:00
public function __construct(callable $callback, string $name, ?int $interval);
2020-07-24 19:24:04 +02:00
/**
* Get name of the loop, passed to the constructor.
*
* @return string
*/
2020-07-24 19:28:17 +02:00
public function __toString(): string;
2023-01-22 21:59:13 +01:00
/**
* Stops loop.
*/
public function stop(): void;
2020-07-24 19:24:04 +02:00
}
2020-07-21 22:12:34 +02:00
```
2020-07-24 19:24:04 +02:00
`PeriodicLoop` runs a callback at a periodic interval.
2023-01-22 21:59:13 +01:00
The loop can be stopped from the outside by using `stop()` and from the inside by returning `true` .