Timer.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. <?php
  2. /**
  3. * This file is part of workerman.
  4. *
  5. * Licensed under The MIT License
  6. * For full copyright and license information, please see the MIT-LICENSE.txt
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @author walkor<walkor@workerman.net>
  10. * @copyright walkor<walkor@workerman.net>
  11. * @link http://www.workerman.net/
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Workerman\Lib;
  15. use Workerman\Events\EventInterface;
  16. use Workerman\Worker;
  17. use Exception;
  18. /**
  19. * Timer.
  20. *
  21. * example:
  22. * Workerman\Lib\Timer::add($time_interval, callback, array($arg1, $arg2..));
  23. */
  24. class Timer
  25. {
  26. /**
  27. * Tasks that based on ALARM signal.
  28. * [
  29. * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
  30. * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]],
  31. * ..
  32. * ]
  33. *
  34. * @var array
  35. */
  36. protected static $_tasks = array();
  37. /**
  38. * event
  39. *
  40. * @var EventInterface
  41. */
  42. protected static $_event = null;
  43. /**
  44. * Init.
  45. *
  46. * @param EventInterface $event
  47. * @return void
  48. */
  49. public static function init($event = null)
  50. {
  51. if ($event) {
  52. self::$_event = $event;
  53. } else {
  54. if (\function_exists('pcntl_signal')) {
  55. \pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false);
  56. }
  57. }
  58. }
  59. /**
  60. * ALARM signal handler.
  61. *
  62. * @return void
  63. */
  64. public static function signalHandle()
  65. {
  66. if (!self::$_event) {
  67. \pcntl_alarm(1);
  68. self::tick();
  69. }
  70. }
  71. /**
  72. * Add a timer.
  73. *
  74. * @param float $time_interval
  75. * @param callable $func
  76. * @param mixed $args
  77. * @param bool $persistent
  78. * @return int|false
  79. */
  80. public static function add($time_interval, $func, $args = array(), $persistent = true)
  81. {
  82. if ($time_interval <= 0) {
  83. Worker::safeEcho(new Exception("bad time_interval"));
  84. return false;
  85. }
  86. if ($args === null) {
  87. $args = [];
  88. }
  89. if (self::$_event) {
  90. return self::$_event->add($time_interval,
  91. $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args);
  92. }
  93. if (!\is_callable($func)) {
  94. Worker::safeEcho(new Exception("not callable"));
  95. return false;
  96. }
  97. if (empty(self::$_tasks)) {
  98. \pcntl_alarm(1);
  99. }
  100. $time_now = \time();
  101. $run_time = $time_now + $time_interval;
  102. if (!isset(self::$_tasks[$run_time])) {
  103. self::$_tasks[$run_time] = array();
  104. }
  105. self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval);
  106. return 1;
  107. }
  108. /**
  109. * Tick.
  110. *
  111. * @return void
  112. */
  113. public static function tick()
  114. {
  115. if (empty(self::$_tasks)) {
  116. \pcntl_alarm(0);
  117. return;
  118. }
  119. $time_now = \time();
  120. foreach (self::$_tasks as $run_time => $task_data) {
  121. if ($time_now >= $run_time) {
  122. foreach ($task_data as $index => $one_task) {
  123. $task_func = $one_task[0];
  124. $task_args = $one_task[1];
  125. $persistent = $one_task[2];
  126. $time_interval = $one_task[3];
  127. try {
  128. \call_user_func_array($task_func, $task_args);
  129. } catch (\Exception $e) {
  130. Worker::safeEcho($e);
  131. }
  132. if ($persistent) {
  133. self::add($time_interval, $task_func, $task_args);
  134. }
  135. }
  136. unset(self::$_tasks[$run_time]);
  137. }
  138. }
  139. }
  140. /**
  141. * Remove a timer.
  142. *
  143. * @param mixed $timer_id
  144. * @return bool
  145. */
  146. public static function del($timer_id)
  147. {
  148. if (self::$_event) {
  149. return self::$_event->del($timer_id, EventInterface::EV_TIMER);
  150. }
  151. return false;
  152. }
  153. /**
  154. * Remove all timers.
  155. *
  156. * @return void
  157. */
  158. public static function delAll()
  159. {
  160. self::$_tasks = array();
  161. \pcntl_alarm(0);
  162. if (self::$_event) {
  163. self::$_event->clearAllTimer();
  164. }
  165. }
  166. }