Event.php 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think;
  13. use ReflectionClass;
  14. use ReflectionMethod;
  15. /**
  16. * 事件管理类
  17. * @package think
  18. */
  19. class Event
  20. {
  21. /**
  22. * 监听者
  23. * @var array
  24. */
  25. protected $listener = [];
  26. /**
  27. * 事件别名
  28. * @var array
  29. */
  30. protected $bind = [
  31. 'AppInit' => event\AppInit::class,
  32. 'HttpRun' => event\HttpRun::class,
  33. 'HttpEnd' => event\HttpEnd::class,
  34. 'RouteLoaded' => event\RouteLoaded::class,
  35. 'LogWrite' => event\LogWrite::class,
  36. ];
  37. /**
  38. * 应用对象
  39. * @var App
  40. */
  41. protected $app;
  42. public function __construct(App $app)
  43. {
  44. $this->app = $app;
  45. }
  46. /**
  47. * 批量注册事件监听
  48. * @access public
  49. * @param array $events 事件定义
  50. * @return $this
  51. */
  52. public function listenEvents(array $events)
  53. {
  54. foreach ($events as $event => $listeners) {
  55. if (isset($this->bind[$event])) {
  56. $event = $this->bind[$event];
  57. }
  58. $this->listener[$event] = array_merge($this->listener[$event] ?? [], $listeners);
  59. }
  60. return $this;
  61. }
  62. /**
  63. * 注册事件监听
  64. * @access public
  65. * @param string $event 事件名称
  66. * @param mixed $listener 监听操作(或者类名)
  67. * @param bool $first 是否优先执行
  68. * @return $this
  69. */
  70. public function listen(string $event, $listener, bool $first = false)
  71. {
  72. if (isset($this->bind[$event])) {
  73. $event = $this->bind[$event];
  74. }
  75. if ($first && isset($this->listener[$event])) {
  76. array_unshift($this->listener[$event], $listener);
  77. } else {
  78. $this->listener[$event][] = $listener;
  79. }
  80. return $this;
  81. }
  82. /**
  83. * 是否存在事件监听
  84. * @access public
  85. * @param string $event 事件名称
  86. * @return bool
  87. */
  88. public function hasListener(string $event): bool
  89. {
  90. if (isset($this->bind[$event])) {
  91. $event = $this->bind[$event];
  92. }
  93. return isset($this->listener[$event]);
  94. }
  95. /**
  96. * 移除事件监听
  97. * @access public
  98. * @param string $event 事件名称
  99. * @return void
  100. */
  101. public function remove(string $event): void
  102. {
  103. if (isset($this->bind[$event])) {
  104. $event = $this->bind[$event];
  105. }
  106. unset($this->listener[$event]);
  107. }
  108. /**
  109. * 指定事件别名标识 便于调用
  110. * @access public
  111. * @param array $events 事件别名
  112. * @return $this
  113. */
  114. public function bind(array $events)
  115. {
  116. $this->bind = array_merge($this->bind, $events);
  117. return $this;
  118. }
  119. /**
  120. * 注册事件订阅者
  121. * @access public
  122. * @param mixed $subscriber 订阅者
  123. * @return $this
  124. */
  125. public function subscribe($subscriber)
  126. {
  127. $subscribers = (array) $subscriber;
  128. foreach ($subscribers as $subscriber) {
  129. if (is_string($subscriber)) {
  130. $subscriber = $this->app->make($subscriber);
  131. }
  132. if (method_exists($subscriber, 'subscribe')) {
  133. // 手动订阅
  134. $subscriber->subscribe($this);
  135. } else {
  136. // 智能订阅
  137. $this->observe($subscriber);
  138. }
  139. }
  140. return $this;
  141. }
  142. /**
  143. * 自动注册事件观察者
  144. * @access public
  145. * @param string|object $observer 观察者
  146. * @param null|string $prefix 事件名前缀
  147. * @return $this
  148. */
  149. public function observe($observer, string $prefix = '')
  150. {
  151. if (is_string($observer)) {
  152. $observer = $this->app->make($observer);
  153. }
  154. $reflect = new ReflectionClass($observer);
  155. $methods = $reflect->getMethods(ReflectionMethod::IS_PUBLIC);
  156. if (empty($prefix) && $reflect->hasProperty('eventPrefix')) {
  157. $reflectProperty = $reflect->getProperty('eventPrefix');
  158. $reflectProperty->setAccessible(true);
  159. $prefix = $reflectProperty->getValue($observer);
  160. }
  161. foreach ($methods as $method) {
  162. $name = $method->getName();
  163. if (0 === strpos($name, 'on')) {
  164. $this->listen($prefix . substr($name, 2), [$observer, $name]);
  165. }
  166. }
  167. return $this;
  168. }
  169. /**
  170. * 触发事件
  171. * @access public
  172. * @param string|object $event 事件名称
  173. * @param mixed $params 传入参数
  174. * @param bool $once 只获取一个有效返回值
  175. * @return mixed
  176. */
  177. public function trigger($event, $params = null, bool $once = false)
  178. {
  179. if (is_object($event)) {
  180. $params = $event;
  181. $event = get_class($event);
  182. }
  183. if (isset($this->bind[$event])) {
  184. $event = $this->bind[$event];
  185. }
  186. $result = [];
  187. $listeners = $this->listener[$event] ?? [];
  188. $listeners = array_unique($listeners, SORT_REGULAR);
  189. foreach ($listeners as $key => $listener) {
  190. $result[$key] = $this->dispatch($listener, $params);
  191. if (false === $result[$key] || (!is_null($result[$key]) && $once)) {
  192. break;
  193. }
  194. }
  195. return $once ? end($result) : $result;
  196. }
  197. /**
  198. * 触发事件(只获取一个有效返回值)
  199. * @param $event
  200. * @param null $params
  201. * @return mixed
  202. */
  203. public function until($event, $params = null)
  204. {
  205. return $this->trigger($event, $params, true);
  206. }
  207. /**
  208. * 执行事件调度
  209. * @access protected
  210. * @param mixed $event 事件方法
  211. * @param mixed $params 参数
  212. * @return mixed
  213. */
  214. protected function dispatch($event, $params = null)
  215. {
  216. if (!is_string($event)) {
  217. $call = $event;
  218. } elseif (strpos($event, '::')) {
  219. $call = $event;
  220. } else {
  221. $obj = $this->app->make($event);
  222. $call = [$obj, 'handle'];
  223. }
  224. return $this->app->invoke($call, [$params]);
  225. }
  226. }