1: <?php
2:
3: namespace React\EventLoop\Timer;
4:
5: use SplObjectStorage;
6: use SplPriorityQueue;
7:
8: class Timers
9: {
10: private $time;
11: private $timers;
12: private $scheduler;
13:
14: public function __construct()
15: {
16: $this->timers = new SplObjectStorage();
17: $this->scheduler = new SplPriorityQueue();
18: }
19:
20: public function updateTime()
21: {
22: return $this->time = microtime(true);
23: }
24:
25: public function getTime()
26: {
27: return $this->time ?: $this->updateTime();
28: }
29:
30: public function add(TimerInterface $timer)
31: {
32: $interval = $timer->getInterval();
33: $scheduledAt = $interval + microtime(true);
34:
35: $this->timers->attach($timer, $scheduledAt);
36: $this->scheduler->insert($timer, -$scheduledAt);
37: }
38:
39: public function contains(TimerInterface $timer)
40: {
41: return $this->timers->contains($timer);
42: }
43:
44: public function cancel(TimerInterface $timer)
45: {
46: $this->timers->detach($timer);
47: }
48:
49: public function getFirst()
50: {
51: while ($this->scheduler->count()) {
52: $timer = $this->scheduler->top();
53:
54: if ($this->timers->contains($timer)) {
55: return $this->timers[$timer];
56: }
57:
58: $this->scheduler->extract();
59: }
60:
61: return null;
62: }
63:
64: public function isEmpty()
65: {
66: return count($this->timers) === 0;
67: }
68:
69: public function tick()
70: {
71: $time = $this->updateTime();
72: $timers = $this->timers;
73: $scheduler = $this->scheduler;
74:
75: while (!$scheduler->isEmpty()) {
76: $timer = $scheduler->top();
77:
78: if (!isset($timers[$timer])) {
79: $scheduler->extract();
80: $timers->detach($timer);
81:
82: continue;
83: }
84:
85: if ($timers[$timer] >= $time) {
86: break;
87: }
88:
89: $scheduler->extract();
90: call_user_func($timer->getCallback(), $timer);
91:
92: if ($timer->isPeriodic() && isset($timers[$timer])) {
93: $timers[$timer] = $scheduledAt = $timer->getInterval() + $time;
94: $scheduler->insert($timer, -$scheduledAt);
95: } else {
96: $timers->detach($timer);
97: }
98: }
99: }
100: }
101: