LoopInterface.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. <?php
  2. namespace React\EventLoop;
  3. interface LoopInterface
  4. {
  5. /**
  6. * [Advanced] Register a listener to be notified when a stream is ready to read.
  7. *
  8. * Note that this low-level API is considered advanced usage.
  9. * Most use cases should probably use the higher-level
  10. * [readable Stream API](https://github.com/reactphp/stream#readablestreaminterface)
  11. * instead.
  12. *
  13. * The first parameter MUST be a valid stream resource that supports
  14. * checking whether it is ready to read by this loop implementation.
  15. * A single stream resource MUST NOT be added more than once.
  16. * Instead, either call [`removeReadStream()`](#removereadstream) first or
  17. * react to this event with a single listener and then dispatch from this
  18. * listener. This method MAY throw an `Exception` if the given resource type
  19. * is not supported by this loop implementation.
  20. *
  21. * The second parameter MUST be a listener callback function that accepts
  22. * the stream resource as its only parameter.
  23. * If you don't use the stream resource inside your listener callback function
  24. * you MAY use a function which has no parameters at all.
  25. *
  26. * The listener callback function MUST NOT throw an `Exception`.
  27. * The return value of the listener callback function will be ignored and has
  28. * no effect, so for performance reasons you're recommended to not return
  29. * any excessive data structures.
  30. *
  31. * If you want to access any variables within your callback function, you
  32. * can bind arbitrary data to a callback closure like this:
  33. *
  34. * ```php
  35. * $loop->addReadStream($stream, function ($stream) use ($name) {
  36. * echo $name . ' said: ' . fread($stream);
  37. * });
  38. * ```
  39. *
  40. * See also [example #11](examples).
  41. *
  42. * You can invoke [`removeReadStream()`](#removereadstream) to remove the
  43. * read event listener for this stream.
  44. *
  45. * The execution order of listeners when multiple streams become ready at
  46. * the same time is not guaranteed.
  47. *
  48. * @param resource $stream The PHP stream resource to check.
  49. * @param callable $listener Invoked when the stream is ready.
  50. * @throws \Exception if the given resource type is not supported by this loop implementation
  51. * @see self::removeReadStream()
  52. */
  53. public function addReadStream($stream, $listener);
  54. /**
  55. * [Advanced] Register a listener to be notified when a stream is ready to write.
  56. *
  57. * Note that this low-level API is considered advanced usage.
  58. * Most use cases should probably use the higher-level
  59. * [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface)
  60. * instead.
  61. *
  62. * The first parameter MUST be a valid stream resource that supports
  63. * checking whether it is ready to write by this loop implementation.
  64. * A single stream resource MUST NOT be added more than once.
  65. * Instead, either call [`removeWriteStream()`](#removewritestream) first or
  66. * react to this event with a single listener and then dispatch from this
  67. * listener. This method MAY throw an `Exception` if the given resource type
  68. * is not supported by this loop implementation.
  69. *
  70. * The second parameter MUST be a listener callback function that accepts
  71. * the stream resource as its only parameter.
  72. * If you don't use the stream resource inside your listener callback function
  73. * you MAY use a function which has no parameters at all.
  74. *
  75. * The listener callback function MUST NOT throw an `Exception`.
  76. * The return value of the listener callback function will be ignored and has
  77. * no effect, so for performance reasons you're recommended to not return
  78. * any excessive data structures.
  79. *
  80. * If you want to access any variables within your callback function, you
  81. * can bind arbitrary data to a callback closure like this:
  82. *
  83. * ```php
  84. * $loop->addWriteStream($stream, function ($stream) use ($name) {
  85. * fwrite($stream, 'Hello ' . $name);
  86. * });
  87. * ```
  88. *
  89. * See also [example #12](examples).
  90. *
  91. * You can invoke [`removeWriteStream()`](#removewritestream) to remove the
  92. * write event listener for this stream.
  93. *
  94. * The execution order of listeners when multiple streams become ready at
  95. * the same time is not guaranteed.
  96. *
  97. * Some event loop implementations are known to only trigger the listener if
  98. * the stream *becomes* readable (edge-triggered) and may not trigger if the
  99. * stream has already been readable from the beginning.
  100. * This also implies that a stream may not be recognized as readable when data
  101. * is still left in PHP's internal stream buffers.
  102. * As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
  103. * to disable PHP's internal read buffer in this case.
  104. *
  105. * @param resource $stream The PHP stream resource to check.
  106. * @param callable $listener Invoked when the stream is ready.
  107. * @throws \Exception if the given resource type is not supported by this loop implementation
  108. * @see self::removeWriteStream()
  109. */
  110. public function addWriteStream($stream, $listener);
  111. /**
  112. * Remove the read event listener for the given stream.
  113. *
  114. * Removing a stream from the loop that has already been removed or trying
  115. * to remove a stream that was never added or is invalid has no effect.
  116. *
  117. * @param resource $stream The PHP stream resource.
  118. */
  119. public function removeReadStream($stream);
  120. /**
  121. * Remove the write event listener for the given stream.
  122. *
  123. * Removing a stream from the loop that has already been removed or trying
  124. * to remove a stream that was never added or is invalid has no effect.
  125. *
  126. * @param resource $stream The PHP stream resource.
  127. */
  128. public function removeWriteStream($stream);
  129. /**
  130. * Enqueue a callback to be invoked once after the given interval.
  131. *
  132. * The second parameter MUST be a timer callback function that accepts
  133. * the timer instance as its only parameter.
  134. * If you don't use the timer instance inside your timer callback function
  135. * you MAY use a function which has no parameters at all.
  136. *
  137. * The timer callback function MUST NOT throw an `Exception`.
  138. * The return value of the timer callback function will be ignored and has
  139. * no effect, so for performance reasons you're recommended to not return
  140. * any excessive data structures.
  141. *
  142. * This method returns a timer instance. The same timer instance will also be
  143. * passed into the timer callback function as described above.
  144. * You can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer.
  145. * Unlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure
  146. * the callback will be invoked only once after the given interval.
  147. *
  148. * ```php
  149. * $loop->addTimer(0.8, function () {
  150. * echo 'world!' . PHP_EOL;
  151. * });
  152. *
  153. * $loop->addTimer(0.3, function () {
  154. * echo 'hello ';
  155. * });
  156. * ```
  157. *
  158. * See also [example #1](examples).
  159. *
  160. * If you want to access any variables within your callback function, you
  161. * can bind arbitrary data to a callback closure like this:
  162. *
  163. * ```php
  164. * function hello($name, LoopInterface $loop)
  165. * {
  166. * $loop->addTimer(1.0, function () use ($name) {
  167. * echo "hello $name\n";
  168. * });
  169. * }
  170. *
  171. * hello('Tester', $loop);
  172. * ```
  173. *
  174. * This interface does not enforce any particular timer resolution, so
  175. * special care may have to be taken if you rely on very high precision with
  176. * millisecond accuracy or below. Event loop implementations SHOULD work on
  177. * a best effort basis and SHOULD provide at least millisecond accuracy
  178. * unless otherwise noted. Many existing event loop implementations are
  179. * known to provide microsecond accuracy, but it's generally not recommended
  180. * to rely on this high precision.
  181. *
  182. * Similarly, the execution order of timers scheduled to execute at the
  183. * same time (within its possible accuracy) is not guaranteed.
  184. *
  185. * This interface suggests that event loop implementations SHOULD use a
  186. * monotonic time source if available. Given that a monotonic time source is
  187. * only available as of PHP 7.3 by default, event loop implementations MAY
  188. * fall back to using wall-clock time.
  189. * While this does not affect many common use cases, this is an important
  190. * distinction for programs that rely on a high time precision or on systems
  191. * that are subject to discontinuous time adjustments (time jumps).
  192. * This means that if you schedule a timer to trigger in 30s and then adjust
  193. * your system time forward by 20s, the timer SHOULD still trigger in 30s.
  194. * See also [event loop implementations](#loop-implementations) for more details.
  195. *
  196. * @param int|float $interval The number of seconds to wait before execution.
  197. * @param callable $callback The callback to invoke.
  198. *
  199. * @return TimerInterface
  200. */
  201. public function addTimer($interval, $callback);
  202. /**
  203. * Enqueue a callback to be invoked repeatedly after the given interval.
  204. *
  205. * The second parameter MUST be a timer callback function that accepts
  206. * the timer instance as its only parameter.
  207. * If you don't use the timer instance inside your timer callback function
  208. * you MAY use a function which has no parameters at all.
  209. *
  210. * The timer callback function MUST NOT throw an `Exception`.
  211. * The return value of the timer callback function will be ignored and has
  212. * no effect, so for performance reasons you're recommended to not return
  213. * any excessive data structures.
  214. *
  215. * This method returns a timer instance. The same timer instance will also be
  216. * passed into the timer callback function as described above.
  217. * Unlike [`addTimer()`](#addtimer), this method will ensure the callback
  218. * will be invoked infinitely after the given interval or until you invoke
  219. * [`cancelTimer`](#canceltimer).
  220. *
  221. * ```php
  222. * $timer = $loop->addPeriodicTimer(0.1, function () {
  223. * echo 'tick!' . PHP_EOL;
  224. * });
  225. *
  226. * $loop->addTimer(1.0, function () use ($loop, $timer) {
  227. * $loop->cancelTimer($timer);
  228. * echo 'Done' . PHP_EOL;
  229. * });
  230. * ```
  231. *
  232. * See also [example #2](examples).
  233. *
  234. * If you want to limit the number of executions, you can bind
  235. * arbitrary data to a callback closure like this:
  236. *
  237. * ```php
  238. * function hello($name, LoopInterface $loop)
  239. * {
  240. * $n = 3;
  241. * $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {
  242. * if ($n > 0) {
  243. * --$n;
  244. * echo "hello $name\n";
  245. * } else {
  246. * $loop->cancelTimer($timer);
  247. * }
  248. * });
  249. * }
  250. *
  251. * hello('Tester', $loop);
  252. * ```
  253. *
  254. * This interface does not enforce any particular timer resolution, so
  255. * special care may have to be taken if you rely on very high precision with
  256. * millisecond accuracy or below. Event loop implementations SHOULD work on
  257. * a best effort basis and SHOULD provide at least millisecond accuracy
  258. * unless otherwise noted. Many existing event loop implementations are
  259. * known to provide microsecond accuracy, but it's generally not recommended
  260. * to rely on this high precision.
  261. *
  262. * Similarly, the execution order of timers scheduled to execute at the
  263. * same time (within its possible accuracy) is not guaranteed.
  264. *
  265. * This interface suggests that event loop implementations SHOULD use a
  266. * monotonic time source if available. Given that a monotonic time source is
  267. * only available as of PHP 7.3 by default, event loop implementations MAY
  268. * fall back to using wall-clock time.
  269. * While this does not affect many common use cases, this is an important
  270. * distinction for programs that rely on a high time precision or on systems
  271. * that are subject to discontinuous time adjustments (time jumps).
  272. * This means that if you schedule a timer to trigger in 30s and then adjust
  273. * your system time forward by 20s, the timer SHOULD still trigger in 30s.
  274. * See also [event loop implementations](#loop-implementations) for more details.
  275. *
  276. * Additionally, periodic timers may be subject to timer drift due to
  277. * re-scheduling after each invocation. As such, it's generally not
  278. * recommended to rely on this for high precision intervals with millisecond
  279. * accuracy or below.
  280. *
  281. * @param int|float $interval The number of seconds to wait before execution.
  282. * @param callable $callback The callback to invoke.
  283. *
  284. * @return TimerInterface
  285. */
  286. public function addPeriodicTimer($interval, $callback);
  287. /**
  288. * Cancel a pending timer.
  289. *
  290. * See also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples).
  291. *
  292. * Calling this method on a timer instance that has not been added to this
  293. * loop instance or on a timer that has already been cancelled has no effect.
  294. *
  295. * @param TimerInterface $timer The timer to cancel.
  296. *
  297. * @return void
  298. */
  299. public function cancelTimer(TimerInterface $timer);
  300. /**
  301. * Schedule a callback to be invoked on a future tick of the event loop.
  302. *
  303. * This works very much similar to timers with an interval of zero seconds,
  304. * but does not require the overhead of scheduling a timer queue.
  305. *
  306. * The tick callback function MUST be able to accept zero parameters.
  307. *
  308. * The tick callback function MUST NOT throw an `Exception`.
  309. * The return value of the tick callback function will be ignored and has
  310. * no effect, so for performance reasons you're recommended to not return
  311. * any excessive data structures.
  312. *
  313. * If you want to access any variables within your callback function, you
  314. * can bind arbitrary data to a callback closure like this:
  315. *
  316. * ```php
  317. * function hello($name, LoopInterface $loop)
  318. * {
  319. * $loop->futureTick(function () use ($name) {
  320. * echo "hello $name\n";
  321. * });
  322. * }
  323. *
  324. * hello('Tester', $loop);
  325. * ```
  326. *
  327. * Unlike timers, tick callbacks are guaranteed to be executed in the order
  328. * they are enqueued.
  329. * Also, once a callback is enqueued, there's no way to cancel this operation.
  330. *
  331. * This is often used to break down bigger tasks into smaller steps (a form
  332. * of cooperative multitasking).
  333. *
  334. * ```php
  335. * $loop->futureTick(function () {
  336. * echo 'b';
  337. * });
  338. * $loop->futureTick(function () {
  339. * echo 'c';
  340. * });
  341. * echo 'a';
  342. * ```
  343. *
  344. * See also [example #3](examples).
  345. *
  346. * @param callable $listener The callback to invoke.
  347. *
  348. * @return void
  349. */
  350. public function futureTick($listener);
  351. /**
  352. * Register a listener to be notified when a signal has been caught by this process.
  353. *
  354. * This is useful to catch user interrupt signals or shutdown signals from
  355. * tools like `supervisor` or `systemd`.
  356. *
  357. * The second parameter MUST be a listener callback function that accepts
  358. * the signal as its only parameter.
  359. * If you don't use the signal inside your listener callback function
  360. * you MAY use a function which has no parameters at all.
  361. *
  362. * The listener callback function MUST NOT throw an `Exception`.
  363. * The return value of the listener callback function will be ignored and has
  364. * no effect, so for performance reasons you're recommended to not return
  365. * any excessive data structures.
  366. *
  367. * ```php
  368. * $loop->addSignal(SIGINT, function (int $signal) {
  369. * echo 'Caught user interrupt signal' . PHP_EOL;
  370. * });
  371. * ```
  372. *
  373. * See also [example #4](examples).
  374. *
  375. * Signaling is only available on Unix-like platforms, Windows isn't
  376. * supported due to operating system limitations.
  377. * This method may throw a `BadMethodCallException` if signals aren't
  378. * supported on this platform, for example when required extensions are
  379. * missing.
  380. *
  381. * **Note: A listener can only be added once to the same signal, any
  382. * attempts to add it more than once will be ignored.**
  383. *
  384. * @param int $signal
  385. * @param callable $listener
  386. *
  387. * @throws \BadMethodCallException when signals aren't supported on this
  388. * platform, for example when required extensions are missing.
  389. *
  390. * @return void
  391. */
  392. public function addSignal($signal, $listener);
  393. /**
  394. * Removes a previously added signal listener.
  395. *
  396. * ```php
  397. * $loop->removeSignal(SIGINT, $listener);
  398. * ```
  399. *
  400. * Any attempts to remove listeners that aren't registered will be ignored.
  401. *
  402. * @param int $signal
  403. * @param callable $listener
  404. *
  405. * @return void
  406. */
  407. public function removeSignal($signal, $listener);
  408. /**
  409. * Run the event loop until there are no more tasks to perform.
  410. *
  411. * For many applications, this method is the only directly visible
  412. * invocation on the event loop.
  413. * As a rule of thumb, it is usually recommended to attach everything to the
  414. * same loop instance and then run the loop once at the bottom end of the
  415. * application.
  416. *
  417. * ```php
  418. * $loop->run();
  419. * ```
  420. *
  421. * This method will keep the loop running until there are no more tasks
  422. * to perform. In other words: This method will block until the last
  423. * timer, stream and/or signal has been removed.
  424. *
  425. * Likewise, it is imperative to ensure the application actually invokes
  426. * this method once. Adding listeners to the loop and missing to actually
  427. * run it will result in the application exiting without actually waiting
  428. * for any of the attached listeners.
  429. *
  430. * This method MUST NOT be called while the loop is already running.
  431. * This method MAY be called more than once after it has explicitly been
  432. * [`stop()`ped](#stop) or after it automatically stopped because it
  433. * previously did no longer have anything to do.
  434. *
  435. * @return void
  436. */
  437. public function run();
  438. /**
  439. * Instruct a running event loop to stop.
  440. *
  441. * This method is considered advanced usage and should be used with care.
  442. * As a rule of thumb, it is usually recommended to let the loop stop
  443. * only automatically when it no longer has anything to do.
  444. *
  445. * This method can be used to explicitly instruct the event loop to stop:
  446. *
  447. * ```php
  448. * $loop->addTimer(3.0, function () use ($loop) {
  449. * $loop->stop();
  450. * });
  451. * ```
  452. *
  453. * Calling this method on a loop instance that is not currently running or
  454. * on a loop instance that has already been stopped has no effect.
  455. *
  456. * @return void
  457. */
  458. public function stop();
  459. }