friendship ended with social-app. php is my new best friend
1<?php
2
3namespace React\EventLoop;
4
5use BadMethodCallException;
6use libev\EventLoop;
7use libev\IOEvent;
8use libev\SignalEvent;
9use libev\TimerEvent;
10use React\EventLoop\Tick\FutureTickQueue;
11use React\EventLoop\Timer\Timer;
12use SplObjectStorage;
13
14/**
15 * [Deprecated] An `ext-libev` based event loop.
16 *
17 * This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev),
18 * that provides an interface to `libev` library.
19 * `libev` itself supports a number of system-specific backends (epoll, kqueue).
20 *
21 * This loop does only work with PHP 5.
22 * An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8)
23 * to happen any time soon.
24 *
25 * @see https://github.com/m4rw3r/php-libev
26 * @see https://gist.github.com/1688204
27 * @deprecated 1.2.0, use [`ExtEvLoop`](#extevloop) instead.
28 */
29final class ExtLibevLoop implements LoopInterface
30{
31 private $loop;
32 private $futureTickQueue;
33 private $timerEvents;
34 private $readEvents = array();
35 private $writeEvents = array();
36 private $running;
37 private $signals;
38 private $signalEvents = array();
39
40 public function __construct()
41 {
42 if (!\class_exists('libev\EventLoop', false)) {
43 throw new BadMethodCallException('Cannot create ExtLibevLoop, ext-libev extension missing');
44 }
45
46 $this->loop = new EventLoop();
47 $this->futureTickQueue = new FutureTickQueue();
48 $this->timerEvents = new SplObjectStorage();
49 $this->signals = new SignalsHandler();
50 }
51
52 public function addReadStream($stream, $listener)
53 {
54 if (isset($this->readEvents[(int) $stream])) {
55 return;
56 }
57
58 $callback = function () use ($stream, $listener) {
59 \call_user_func($listener, $stream);
60 };
61
62 $event = new IOEvent($callback, $stream, IOEvent::READ);
63 $this->loop->add($event);
64
65 $this->readEvents[(int) $stream] = $event;
66 }
67
68 public function addWriteStream($stream, $listener)
69 {
70 if (isset($this->writeEvents[(int) $stream])) {
71 return;
72 }
73
74 $callback = function () use ($stream, $listener) {
75 \call_user_func($listener, $stream);
76 };
77
78 $event = new IOEvent($callback, $stream, IOEvent::WRITE);
79 $this->loop->add($event);
80
81 $this->writeEvents[(int) $stream] = $event;
82 }
83
84 public function removeReadStream($stream)
85 {
86 $key = (int) $stream;
87
88 if (isset($this->readEvents[$key])) {
89 $this->readEvents[$key]->stop();
90 $this->loop->remove($this->readEvents[$key]);
91 unset($this->readEvents[$key]);
92 }
93 }
94
95 public function removeWriteStream($stream)
96 {
97 $key = (int) $stream;
98
99 if (isset($this->writeEvents[$key])) {
100 $this->writeEvents[$key]->stop();
101 $this->loop->remove($this->writeEvents[$key]);
102 unset($this->writeEvents[$key]);
103 }
104 }
105
106 public function addTimer($interval, $callback)
107 {
108 $timer = new Timer( $interval, $callback, false);
109
110 $that = $this;
111 $timers = $this->timerEvents;
112 $callback = function () use ($timer, $timers, $that) {
113 \call_user_func($timer->getCallback(), $timer);
114
115 if ($timers->contains($timer)) {
116 $that->cancelTimer($timer);
117 }
118 };
119
120 $event = new TimerEvent($callback, $timer->getInterval());
121 $this->timerEvents->attach($timer, $event);
122 $this->loop->add($event);
123
124 return $timer;
125 }
126
127 public function addPeriodicTimer($interval, $callback)
128 {
129 $timer = new Timer($interval, $callback, true);
130
131 $callback = function () use ($timer) {
132 \call_user_func($timer->getCallback(), $timer);
133 };
134
135 $event = new TimerEvent($callback, $timer->getInterval(), $timer->getInterval());
136 $this->timerEvents->attach($timer, $event);
137 $this->loop->add($event);
138
139 return $timer;
140 }
141
142 public function cancelTimer(TimerInterface $timer)
143 {
144 if (isset($this->timerEvents[$timer])) {
145 $this->loop->remove($this->timerEvents[$timer]);
146 $this->timerEvents->detach($timer);
147 }
148 }
149
150 public function futureTick($listener)
151 {
152 $this->futureTickQueue->add($listener);
153 }
154
155 public function addSignal($signal, $listener)
156 {
157 $this->signals->add($signal, $listener);
158
159 if (!isset($this->signalEvents[$signal])) {
160 $signals = $this->signals;
161 $this->signalEvents[$signal] = new SignalEvent(function () use ($signals, $signal) {
162 $signals->call($signal);
163 }, $signal);
164 $this->loop->add($this->signalEvents[$signal]);
165 }
166 }
167
168 public function removeSignal($signal, $listener)
169 {
170 $this->signals->remove($signal, $listener);
171
172 if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
173 $this->signalEvents[$signal]->stop();
174 $this->loop->remove($this->signalEvents[$signal]);
175 unset($this->signalEvents[$signal]);
176 }
177 }
178
179 public function run()
180 {
181 $this->running = true;
182
183 while ($this->running) {
184 $this->futureTickQueue->tick();
185
186 $flags = EventLoop::RUN_ONCE;
187 if (!$this->running || !$this->futureTickQueue->isEmpty()) {
188 $flags |= EventLoop::RUN_NOWAIT;
189 } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
190 break;
191 }
192
193 $this->loop->run($flags);
194 }
195 }
196
197 public function stop()
198 {
199 $this->running = false;
200 }
201}