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}