Loop.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <?php
  2. namespace React\EventLoop;
  3. /**
  4. * The `Loop` class exists as a convenient way to get the currently relevant loop
  5. */
  6. final class Loop
  7. {
  8. /**
  9. * @var ?LoopInterface
  10. */
  11. private static $instance;
  12. /** @var bool */
  13. private static $stopped = false;
  14. /**
  15. * Returns the event loop.
  16. * When no loop is set, it will call the factory to create one.
  17. *
  18. * This method always returns an instance implementing `LoopInterface`,
  19. * the actual event loop implementation is an implementation detail.
  20. *
  21. * This method is the preferred way to get the event loop and using
  22. * Factory::create has been deprecated.
  23. *
  24. * @return LoopInterface
  25. */
  26. public static function get()
  27. {
  28. if (self::$instance instanceof LoopInterface) {
  29. return self::$instance;
  30. }
  31. self::$instance = $loop = Factory::create();
  32. // Automatically run loop at end of program, unless already started or stopped explicitly.
  33. // This is tested using child processes, so coverage is actually 100%, see BinTest.
  34. // @codeCoverageIgnoreStart
  35. $hasRun = false;
  36. $loop->futureTick(function () use (&$hasRun) {
  37. $hasRun = true;
  38. });
  39. $stopped =& self::$stopped;
  40. register_shutdown_function(function () use ($loop, &$hasRun, &$stopped) {
  41. // Don't run if we're coming from a fatal error (uncaught exception).
  42. $error = error_get_last();
  43. if ((isset($error['type']) ? $error['type'] : 0) & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) {
  44. return;
  45. }
  46. if (!$hasRun && !$stopped) {
  47. $loop->run();
  48. }
  49. });
  50. // @codeCoverageIgnoreEnd
  51. return self::$instance;
  52. }
  53. /**
  54. * Internal undocumented method, behavior might change or throw in the
  55. * future. Use with caution and at your own risk.
  56. *
  57. * @internal
  58. * @return void
  59. */
  60. public static function set(LoopInterface $loop)
  61. {
  62. self::$instance = $loop;
  63. }
  64. /**
  65. * [Advanced] Register a listener to be notified when a stream is ready to read.
  66. *
  67. * @param resource $stream
  68. * @param callable $listener
  69. * @return void
  70. * @throws \Exception
  71. * @see LoopInterface::addReadStream()
  72. */
  73. public static function addReadStream($stream, $listener)
  74. {
  75. // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
  76. if (self::$instance === null) {
  77. self::get();
  78. }
  79. self::$instance->addReadStream($stream, $listener);
  80. }
  81. /**
  82. * [Advanced] Register a listener to be notified when a stream is ready to write.
  83. *
  84. * @param resource $stream
  85. * @param callable $listener
  86. * @return void
  87. * @throws \Exception
  88. * @see LoopInterface::addWriteStream()
  89. */
  90. public static function addWriteStream($stream, $listener)
  91. {
  92. // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
  93. if (self::$instance === null) {
  94. self::get();
  95. }
  96. self::$instance->addWriteStream($stream, $listener);
  97. }
  98. /**
  99. * Remove the read event listener for the given stream.
  100. *
  101. * @param resource $stream
  102. * @return void
  103. * @see LoopInterface::removeReadStream()
  104. */
  105. public static function removeReadStream($stream)
  106. {
  107. if (self::$instance !== null) {
  108. self::$instance->removeReadStream($stream);
  109. }
  110. }
  111. /**
  112. * Remove the write event listener for the given stream.
  113. *
  114. * @param resource $stream
  115. * @return void
  116. * @see LoopInterface::removeWriteStream()
  117. */
  118. public static function removeWriteStream($stream)
  119. {
  120. if (self::$instance !== null) {
  121. self::$instance->removeWriteStream($stream);
  122. }
  123. }
  124. /**
  125. * Enqueue a callback to be invoked once after the given interval.
  126. *
  127. * @param float $interval
  128. * @param callable $callback
  129. * @return TimerInterface
  130. * @see LoopInterface::addTimer()
  131. */
  132. public static function addTimer($interval, $callback)
  133. {
  134. // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
  135. if (self::$instance === null) {
  136. self::get();
  137. }
  138. return self::$instance->addTimer($interval, $callback);
  139. }
  140. /**
  141. * Enqueue a callback to be invoked repeatedly after the given interval.
  142. *
  143. * @param float $interval
  144. * @param callable $callback
  145. * @return TimerInterface
  146. * @see LoopInterface::addPeriodicTimer()
  147. */
  148. public static function addPeriodicTimer($interval, $callback)
  149. {
  150. // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
  151. if (self::$instance === null) {
  152. self::get();
  153. }
  154. return self::$instance->addPeriodicTimer($interval, $callback);
  155. }
  156. /**
  157. * Cancel a pending timer.
  158. *
  159. * @param TimerInterface $timer
  160. * @return void
  161. * @see LoopInterface::cancelTimer()
  162. */
  163. public static function cancelTimer(TimerInterface $timer)
  164. {
  165. if (self::$instance !== null) {
  166. self::$instance->cancelTimer($timer);
  167. }
  168. }
  169. /**
  170. * Schedule a callback to be invoked on a future tick of the event loop.
  171. *
  172. * @param callable $listener
  173. * @return void
  174. * @see LoopInterface::futureTick()
  175. */
  176. public static function futureTick($listener)
  177. {
  178. // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
  179. if (self::$instance === null) {
  180. self::get();
  181. }
  182. self::$instance->futureTick($listener);
  183. }
  184. /**
  185. * Register a listener to be notified when a signal has been caught by this process.
  186. *
  187. * @param int $signal
  188. * @param callable $listener
  189. * @return void
  190. * @see LoopInterface::addSignal()
  191. */
  192. public static function addSignal($signal, $listener)
  193. {
  194. // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
  195. if (self::$instance === null) {
  196. self::get();
  197. }
  198. self::$instance->addSignal($signal, $listener);
  199. }
  200. /**
  201. * Removes a previously added signal listener.
  202. *
  203. * @param int $signal
  204. * @param callable $listener
  205. * @return void
  206. * @see LoopInterface::removeSignal()
  207. */
  208. public static function removeSignal($signal, $listener)
  209. {
  210. if (self::$instance !== null) {
  211. self::$instance->removeSignal($signal, $listener);
  212. }
  213. }
  214. /**
  215. * Run the event loop until there are no more tasks to perform.
  216. *
  217. * @return void
  218. * @see LoopInterface::run()
  219. */
  220. public static function run()
  221. {
  222. // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
  223. if (self::$instance === null) {
  224. self::get();
  225. }
  226. self::$instance->run();
  227. }
  228. /**
  229. * Instruct a running event loop to stop.
  230. *
  231. * @return void
  232. * @see LoopInterface::stop()
  233. */
  234. public static function stop()
  235. {
  236. self::$stopped = true;
  237. if (self::$instance !== null) {
  238. self::$instance->stop();
  239. }
  240. }
  241. }