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