addReadStream($stream, function ($stream) use ($name) { * echo $name . ' said: ' . fread($stream); * }); * ``` * * See also [example #11](examples). * * You can invoke [`removeReadStream()`](#removereadstream) to remove the * read event listener for this stream. * * The execution order of listeners when multiple streams become ready at * the same time is not guaranteed. * * @param resource $stream The PHP stream resource to check. * @param callable $listener Invoked when the stream is ready. * @throws \Exception if the given resource type is not supported by this loop implementation * @see self::removeReadStream() */ public function addReadStream($stream, $listener); /** * [Advanced] Register a listener to be notified when a stream is ready to write. * * Note that this low-level API is considered advanced usage. * Most use cases should probably use the higher-level * [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface) * instead. * * The first parameter MUST be a valid stream resource that supports * checking whether it is ready to write by this loop implementation. * A single stream resource MUST NOT be added more than once. * Instead, either call [`removeWriteStream()`](#removewritestream) first or * react to this event with a single listener and then dispatch from this * listener. This method MAY throw an `Exception` if the given resource type * is not supported by this loop implementation. * * The second parameter MUST be a listener callback function that accepts * the stream resource as its only parameter. * If you don't use the stream resource inside your listener callback function * you MAY use a function which has no parameters at all. * * The listener callback function MUST NOT throw an `Exception`. * The return value of the listener callback function will be ignored and has * no effect, so for performance reasons you're recommended to not return * any excessive data structures. * * If you want to access any variables within your callback function, you * can bind arbitrary data to a callback closure like this: * * ```php * $loop->addWriteStream($stream, function ($stream) use ($name) { * fwrite($stream, 'Hello ' . $name); * }); * ``` * * See also [example #12](examples). * * You can invoke [`removeWriteStream()`](#removewritestream) to remove the * write event listener for this stream. * * The execution order of listeners when multiple streams become ready at * the same time is not guaranteed. * * Some event loop implementations are known to only trigger the listener if * the stream *becomes* readable (edge-triggered) and may not trigger if the * stream has already been readable from the beginning. * This also implies that a stream may not be recognized as readable when data * is still left in PHP's internal stream buffers. * As such, it's recommended to use `stream_set_read_buffer($stream, 0);` * to disable PHP's internal read buffer in this case. * * @param resource $stream The PHP stream resource to check. * @param callable $listener Invoked when the stream is ready. * @throws \Exception if the given resource type is not supported by this loop implementation * @see self::removeWriteStream() */ public function addWriteStream($stream, $listener); /** * Remove the read event listener for the given stream. * * Removing a stream from the loop that has already been removed or trying * to remove a stream that was never added or is invalid has no effect. * * @param resource $stream The PHP stream resource. */ public function removeReadStream($stream); /** * Remove the write event listener for the given stream. * * Removing a stream from the loop that has already been removed or trying * to remove a stream that was never added or is invalid has no effect. * * @param resource $stream The PHP stream resource. */ public function removeWriteStream($stream); /** * Enqueue a callback to be invoked once after the given interval. * * The second parameter MUST be a timer callback function that accepts * the timer instance as its only parameter. * If you don't use the timer instance inside your timer callback function * you MAY use a function which has no parameters at all. * * The timer callback function MUST NOT throw an `Exception`. * The return value of the timer callback function will be ignored and has * no effect, so for performance reasons you're recommended to not return * any excessive data structures. * * This method returns a timer instance. The same timer instance will also be * passed into the timer callback function as described above. * You can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer. * Unlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure * the callback will be invoked only once after the given interval. * * ```php * $loop->addTimer(0.8, function () { * echo 'world!' . PHP_EOL; * }); * * $loop->addTimer(0.3, function () { * echo 'hello '; * }); * ``` * * See also [example #1](examples). * * If you want to access any variables within your callback function, you * can bind arbitrary data to a callback closure like this: * * ```php * function hello($name, LoopInterface $loop) * { * $loop->addTimer(1.0, function () use ($name) { * echo "hello $name\n"; * }); * } * * hello('Tester', $loop); * ``` * * This interface does not enforce any particular timer resolution, so * special care may have to be taken if you rely on very high precision with * millisecond accuracy or below. Event loop implementations SHOULD work on * a best effort basis and SHOULD provide at least millisecond accuracy * unless otherwise noted. Many existing event loop implementations are * known to provide microsecond accuracy, but it's generally not recommended * to rely on this high precision. * * Similarly, the execution order of timers scheduled to execute at the * same time (within its possible accuracy) is not guaranteed. * * This interface suggests that event loop implementations SHOULD use a * monotonic time source if available. Given that a monotonic time source is * only available as of PHP 7.3 by default, event loop implementations MAY * fall back to using wall-clock time. * While this does not affect many common use cases, this is an important * distinction for programs that rely on a high time precision or on systems * that are subject to discontinuous time adjustments (time jumps). * This means that if you schedule a timer to trigger in 30s and then adjust * your system time forward by 20s, the timer SHOULD still trigger in 30s. * See also [event loop implementations](#loop-implementations) for more details. * * @param int|float $interval The number of seconds to wait before execution. * @param callable $callback The callback to invoke. * * @return TimerInterface */ public function addTimer($interval, $callback); /** * Enqueue a callback to be invoked repeatedly after the given interval. * * The second parameter MUST be a timer callback function that accepts * the timer instance as its only parameter. * If you don't use the timer instance inside your timer callback function * you MAY use a function which has no parameters at all. * * The timer callback function MUST NOT throw an `Exception`. * The return value of the timer callback function will be ignored and has * no effect, so for performance reasons you're recommended to not return * any excessive data structures. * * This method returns a timer instance. The same timer instance will also be * passed into the timer callback function as described above. * Unlike [`addTimer()`](#addtimer), this method will ensure the callback * will be invoked infinitely after the given interval or until you invoke * [`cancelTimer`](#canceltimer). * * ```php * $timer = $loop->addPeriodicTimer(0.1, function () { * echo 'tick!' . PHP_EOL; * }); * * $loop->addTimer(1.0, function () use ($loop, $timer) { * $loop->cancelTimer($timer); * echo 'Done' . PHP_EOL; * }); * ``` * * See also [example #2](examples). * * If you want to limit the number of executions, you can bind * arbitrary data to a callback closure like this: * * ```php * function hello($name, LoopInterface $loop) * { * $n = 3; * $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) { * if ($n > 0) { * --$n; * echo "hello $name\n"; * } else { * $loop->cancelTimer($timer); * } * }); * } * * hello('Tester', $loop); * ``` * * This interface does not enforce any particular timer resolution, so * special care may have to be taken if you rely on very high precision with * millisecond accuracy or below. Event loop implementations SHOULD work on * a best effort basis and SHOULD provide at least millisecond accuracy * unless otherwise noted. Many existing event loop implementations are * known to provide microsecond accuracy, but it's generally not recommended * to rely on this high precision. * * Similarly, the execution order of timers scheduled to execute at the * same time (within its possible accuracy) is not guaranteed. * * This interface suggests that event loop implementations SHOULD use a * monotonic time source if available. Given that a monotonic time source is * only available as of PHP 7.3 by default, event loop implementations MAY * fall back to using wall-clock time. * While this does not affect many common use cases, this is an important * distinction for programs that rely on a high time precision or on systems * that are subject to discontinuous time adjustments (time jumps). * This means that if you schedule a timer to trigger in 30s and then adjust * your system time forward by 20s, the timer SHOULD still trigger in 30s. * See also [event loop implementations](#loop-implementations) for more details. * * Additionally, periodic timers may be subject to timer drift due to * re-scheduling after each invocation. As such, it's generally not * recommended to rely on this for high precision intervals with millisecond * accuracy or below. * * @param int|float $interval The number of seconds to wait before execution. * @param callable $callback The callback to invoke. * * @return TimerInterface */ public function addPeriodicTimer($interval, $callback); /** * Cancel a pending timer. * * See also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples). * * Calling this method on a timer instance that has not been added to this * loop instance or on a timer that has already been cancelled has no effect. * * @param TimerInterface $timer The timer to cancel. * * @return void */ public function cancelTimer(TimerInterface $timer); /** * Schedule a callback to be invoked on a future tick of the event loop. * * This works very much similar to timers with an interval of zero seconds, * but does not require the overhead of scheduling a timer queue. * * The tick callback function MUST be able to accept zero parameters. * * The tick callback function MUST NOT throw an `Exception`. * The return value of the tick callback function will be ignored and has * no effect, so for performance reasons you're recommended to not return * any excessive data structures. * * If you want to access any variables within your callback function, you * can bind arbitrary data to a callback closure like this: * * ```php * function hello($name, LoopInterface $loop) * { * $loop->futureTick(function () use ($name) { * echo "hello $name\n"; * }); * } * * hello('Tester', $loop); * ``` * * Unlike timers, tick callbacks are guaranteed to be executed in the order * they are enqueued. * Also, once a callback is enqueued, there's no way to cancel this operation. * * This is often used to break down bigger tasks into smaller steps (a form * of cooperative multitasking). * * ```php * $loop->futureTick(function () { * echo 'b'; * }); * $loop->futureTick(function () { * echo 'c'; * }); * echo 'a'; * ``` * * See also [example #3](examples). * * @param callable $listener The callback to invoke. * * @return void */ public function futureTick($listener); /** * Register a listener to be notified when a signal has been caught by this process. * * This is useful to catch user interrupt signals or shutdown signals from * tools like `supervisor` or `systemd`. * * The second parameter MUST be a listener callback function that accepts * the signal as its only parameter. * If you don't use the signal inside your listener callback function * you MAY use a function which has no parameters at all. * * The listener callback function MUST NOT throw an `Exception`. * The return value of the listener callback function will be ignored and has * no effect, so for performance reasons you're recommended to not return * any excessive data structures. * * ```php * $loop->addSignal(SIGINT, function (int $signal) { * echo 'Caught user interrupt signal' . PHP_EOL; * }); * ``` * * See also [example #4](examples). * * Signaling is only available on Unix-like platforms, Windows isn't * supported due to operating system limitations. * This method may throw a `BadMethodCallException` if signals aren't * supported on this platform, for example when required extensions are * missing. * * **Note: A listener can only be added once to the same signal, any * attempts to add it more than once will be ignored.** * * @param int $signal * @param callable $listener * * @throws \BadMethodCallException when signals aren't supported on this * platform, for example when required extensions are missing. * * @return void */ public function addSignal($signal, $listener); /** * Removes a previously added signal listener. * * ```php * $loop->removeSignal(SIGINT, $listener); * ``` * * Any attempts to remove listeners that aren't registered will be ignored. * * @param int $signal * @param callable $listener * * @return void */ public function removeSignal($signal, $listener); /** * Run the event loop until there are no more tasks to perform. * * For many applications, this method is the only directly visible * invocation on the event loop. * As a rule of thumb, it is usually recommended to attach everything to the * same loop instance and then run the loop once at the bottom end of the * application. * * ```php * $loop->run(); * ``` * * This method will keep the loop running until there are no more tasks * to perform. In other words: This method will block until the last * timer, stream and/or signal has been removed. * * Likewise, it is imperative to ensure the application actually invokes * this method once. Adding listeners to the loop and missing to actually * run it will result in the application exiting without actually waiting * for any of the attached listeners. * * This method MUST NOT be called while the loop is already running. * This method MAY be called more than once after it has explicitly been * [`stop()`ped](#stop) or after it automatically stopped because it * previously did no longer have anything to do. * * @return void */ public function run(); /** * Instruct a running event loop to stop. * * This method is considered advanced usage and should be used with care. * As a rule of thumb, it is usually recommended to let the loop stop * only automatically when it no longer has anything to do. * * This method can be used to explicitly instruct the event loop to stop: * * ```php * $loop->addTimer(3.0, function () use ($loop) { * $loop->stop(); * }); * ``` * * Calling this method on a loop instance that is not currently running or * on a loop instance that has already been stopped has no effect. * * @return void */ public function stop(); }