2021-03-18 14:56:35 +08:00
|
|
|
|
<?php /** @noinspection PhpUnused */
|
2020-09-29 15:07:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace ZM\Event;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use Doctrine\Common\Annotations\AnnotationException;
|
2021-01-02 13:15:50 +08:00
|
|
|
|
use Error;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
use Exception;
|
2020-12-14 01:24:34 +08:00
|
|
|
|
use ZM\Console\Console;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
use ZM\Exception\InterruptException;
|
2020-12-14 01:24:34 +08:00
|
|
|
|
use ZM\Store\LightCacheInside;
|
|
|
|
|
|
use ZM\Store\Lock\SpinLock;
|
|
|
|
|
|
use ZM\Store\ZMAtomic;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
use ZM\Utils\ZMUtil;
|
|
|
|
|
|
|
|
|
|
|
|
class EventDispatcher
|
|
|
|
|
|
{
|
2021-01-02 13:15:50 +08:00
|
|
|
|
const STATUS_NORMAL = 0; //正常结束
|
|
|
|
|
|
const STATUS_INTERRUPTED = 1; //被interrupt了,不管在什么地方
|
|
|
|
|
|
const STATUS_EXCEPTION = 2; //执行过程中抛出了异常
|
|
|
|
|
|
const STATUS_BEFORE_FAILED = 3; //中间件HandleBefore返回了false,所以不执行此方法
|
|
|
|
|
|
const STATUS_RULE_FAILED = 4; //判断事件执行的规则函数判定为false,所以不执行此方法
|
|
|
|
|
|
|
2020-09-29 15:07:43 +08:00
|
|
|
|
/** @var string */
|
|
|
|
|
|
private $class;
|
|
|
|
|
|
/** @var null|callable */
|
|
|
|
|
|
private $rule = null;
|
|
|
|
|
|
/** @var null|callable */
|
|
|
|
|
|
private $return_func = null;
|
2020-12-14 01:24:34 +08:00
|
|
|
|
/** @var bool */
|
|
|
|
|
|
private $log = false;
|
|
|
|
|
|
/** @var int */
|
2021-03-18 14:56:35 +08:00
|
|
|
|
private $eid;
|
2021-01-02 13:15:50 +08:00
|
|
|
|
/** @var int */
|
|
|
|
|
|
public $status = self::STATUS_NORMAL;
|
|
|
|
|
|
/** @var mixed */
|
|
|
|
|
|
public $store = null;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
|
2020-10-03 23:00:18 +08:00
|
|
|
|
/**
|
2020-12-20 18:08:34 +08:00
|
|
|
|
* @param null $return_var
|
2020-10-03 23:00:18 +08:00
|
|
|
|
* @throws InterruptException
|
|
|
|
|
|
*/
|
2020-12-20 18:08:34 +08:00
|
|
|
|
public static function interrupt($return_var = null) {
|
|
|
|
|
|
throw new InterruptException($return_var);
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-14 01:24:34 +08:00
|
|
|
|
public static function enableEventTrace($event_class) {
|
|
|
|
|
|
SpinLock::lock("_event_trace");
|
|
|
|
|
|
$list = LightCacheInside::get("wait_api", "event_trace");
|
|
|
|
|
|
$list[$event_class] = true;
|
|
|
|
|
|
LightCacheInside::set("wait_api", "event_trace", $list);
|
|
|
|
|
|
SpinLock::unlock("_event_trace");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static function disableEventTrace($event_class) {
|
|
|
|
|
|
SpinLock::lock("_event_trace");
|
|
|
|
|
|
$list = LightCacheInside::get("wait_api", "event_trace");
|
|
|
|
|
|
unset($list[$event_class]);
|
|
|
|
|
|
LightCacheInside::set("wait_api", "event_trace", $list);
|
|
|
|
|
|
SpinLock::unlock("_event_trace");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-09-29 15:07:43 +08:00
|
|
|
|
public function __construct(string $class = '') {
|
|
|
|
|
|
$this->class = $class;
|
2021-03-18 14:56:35 +08:00
|
|
|
|
$this->eid = ZMAtomic::get("_event_id")->add(1);
|
|
|
|
|
|
$list = LightCacheInside::get("wait_api", "event_trace");
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if (isset($list[$class])) $this->log = true;
|
|
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 开始分发事件: " . $class);
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-03-18 14:56:35 +08:00
|
|
|
|
public function setRuleFunction(callable $rule = null): EventDispatcher {
|
2020-09-29 15:07:43 +08:00
|
|
|
|
$this->rule = $rule;
|
|
|
|
|
|
return $this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-03-18 14:56:35 +08:00
|
|
|
|
public function setReturnFunction(callable $return_func): EventDispatcher {
|
2020-09-29 15:07:43 +08:00
|
|
|
|
$this->return_func = $return_func;
|
|
|
|
|
|
return $this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-02 13:15:50 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @param mixed ...$params
|
|
|
|
|
|
* @throws Exception
|
|
|
|
|
|
*/
|
2020-09-29 15:07:43 +08:00
|
|
|
|
public function dispatchEvents(...$params) {
|
|
|
|
|
|
try {
|
2020-11-03 21:02:24 +08:00
|
|
|
|
foreach ((EventManager::$events[$this->class] ?? []) as $v) {
|
2021-01-02 13:15:50 +08:00
|
|
|
|
$this->dispatchEvent($v, $this->rule, ...$params);
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 单一对象 " . $v->class . "::" . $v->method . " 分发结束。");
|
2021-02-09 17:09:09 +08:00
|
|
|
|
if ($this->status == self::STATUS_BEFORE_FAILED || $this->status == self::STATUS_RULE_FAILED) continue;
|
2021-01-02 13:15:50 +08:00
|
|
|
|
if (is_callable($this->return_func) && $this->status === self::STATUS_NORMAL) {
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 单一对象 " . $v->class . "::" . $v->method . " 正在执行返回值处理函数 ...");
|
2021-01-02 13:15:50 +08:00
|
|
|
|
($this->return_func)($this->store);
|
2020-12-14 01:24:34 +08:00
|
|
|
|
}
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
2021-02-09 17:09:09 +08:00
|
|
|
|
if ($this->status === self::STATUS_RULE_FAILED) $this->status = self::STATUS_NORMAL;
|
2021-03-15 02:54:16 +08:00
|
|
|
|
//TODO:没有过滤before的false,可能会导致一些问题,先观望一下
|
2020-09-29 15:07:43 +08:00
|
|
|
|
} catch (InterruptException $e) {
|
2021-01-02 13:15:50 +08:00
|
|
|
|
$this->store = $e->return_var;
|
|
|
|
|
|
$this->status = self::STATUS_INTERRUPTED;
|
2021-01-29 22:27:10 +08:00
|
|
|
|
} catch (Exception | Error $e) {
|
2021-01-02 13:15:50 +08:00
|
|
|
|
$this->status = self::STATUS_EXCEPTION;
|
|
|
|
|
|
throw $e;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-10-03 23:00:18 +08:00
|
|
|
|
/**
|
2021-01-02 13:15:50 +08:00
|
|
|
|
* @param mixed $v
|
2020-10-03 23:00:18 +08:00
|
|
|
|
* @param null $rule_func
|
|
|
|
|
|
* @param mixed ...$params
|
2021-01-02 13:15:50 +08:00
|
|
|
|
* @return bool
|
2021-02-09 17:09:09 +08:00
|
|
|
|
* @throws InterruptException
|
|
|
|
|
|
* @throws AnnotationException
|
2021-03-18 14:56:35 +08:00
|
|
|
|
* @noinspection PhpMissingReturnTypeInspection
|
2020-10-03 23:00:18 +08:00
|
|
|
|
*/
|
2021-01-02 13:15:50 +08:00
|
|
|
|
public function dispatchEvent($v, $rule_func = null, ...$params) {
|
2020-09-29 15:07:43 +08:00
|
|
|
|
$q_c = $v->class;
|
|
|
|
|
|
$q_f = $v->method;
|
2021-01-02 13:15:50 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在判断 " . $q_c . "::" . $q_f . " 方法下的 ruleFunc ...");
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($rule_func !== null && !$rule_func($v)) {
|
2021-01-02 13:15:50 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法下的 ruleFunc 判断为 false, 拒绝执行此方法。");
|
|
|
|
|
|
$this->status = self::STATUS_RULE_FAILED;
|
2020-12-14 01:24:34 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2021-01-02 13:15:50 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法下的 ruleFunc 为真,继续执行方法本身 ...");
|
2020-09-29 15:07:43 +08:00
|
|
|
|
if (isset(EventManager::$middleware_map[$q_c][$q_f])) {
|
|
|
|
|
|
$middlewares = EventManager::$middleware_map[$q_c][$q_f];
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] " . $q_c . "::" . $q_f . " 方法还绑定了 Middleware:" . implode(", ", $middlewares));
|
2020-09-29 15:07:43 +08:00
|
|
|
|
$before_result = true;
|
|
|
|
|
|
$r = [];
|
|
|
|
|
|
foreach ($middlewares as $k => $middleware) {
|
|
|
|
|
|
if (!isset(EventManager::$middlewares[$middleware])) throw new AnnotationException("Annotation parse error: Unknown MiddlewareClass named \"{$middleware}\"!");
|
|
|
|
|
|
$middleware_obj = EventManager::$middlewares[$middleware];
|
|
|
|
|
|
$before = $middleware_obj["class"];
|
|
|
|
|
|
//var_dump($middleware_obj);
|
|
|
|
|
|
$r[$k] = new $before();
|
|
|
|
|
|
$r[$k]->class = $q_c;
|
|
|
|
|
|
$r[$k]->method = $q_f;
|
|
|
|
|
|
if (isset($middleware_obj["before"])) {
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] Middleware 存在前置事件,执行中 ...");
|
2020-09-29 15:07:43 +08:00
|
|
|
|
$rs = $middleware_obj["before"];
|
|
|
|
|
|
$before_result = $r[$k]->$rs(...$params);
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($before_result === false) {
|
|
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] Middleware 前置事件为 false,停止执行原事件,开始执行下一事件。");
|
|
|
|
|
|
break;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] Middleware 前置事件为 true,继续执行原事件。");
|
|
|
|
|
|
}
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($before_result) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
$q_o = ZMUtil::getModInstance($q_c);
|
2021-03-24 23:34:46 +08:00
|
|
|
|
$q_o->_running_annotation = $v;
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在执行方法 " . $q_c . "::" . $q_f . " ...");
|
2021-01-02 13:15:50 +08:00
|
|
|
|
$this->store = $q_o->$q_f(...$params);
|
2020-09-29 15:07:43 +08:00
|
|
|
|
} catch (Exception $e) {
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($e instanceof InterruptException) {
|
|
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 检测到事件阻断调用,正在跳出事件分发器 ...");
|
|
|
|
|
|
throw $e;
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 方法 " . $q_c . "::" . $q_f . " 执行过程中抛出了异常,正在倒序查找 Middleware 中的捕获方法 ...");
|
2020-09-29 15:07:43 +08:00
|
|
|
|
for ($i = count($middlewares) - 1; $i >= 0; --$i) {
|
|
|
|
|
|
$middleware_obj = EventManager::$middlewares[$middlewares[$i]];
|
|
|
|
|
|
if (!isset($middleware_obj["exceptions"])) continue;
|
|
|
|
|
|
foreach ($middleware_obj["exceptions"] as $name => $method) {
|
|
|
|
|
|
if ($e instanceof $name) {
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 方法 " . $q_c . "::" . $q_f . " 的异常 " . get_class($e) . " 被 Middleware:" . $middlewares[$i] . " 下的 " . get_class($r[$i]) . "::" . $method . " 捕获。");
|
2020-09-29 15:07:43 +08:00
|
|
|
|
$r[$i]->$method($e);
|
|
|
|
|
|
self::interrupt();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
throw $e;
|
|
|
|
|
|
}
|
|
|
|
|
|
for ($i = count($middlewares) - 1; $i >= 0; --$i) {
|
|
|
|
|
|
$middleware_obj = EventManager::$middlewares[$middlewares[$i]];
|
|
|
|
|
|
if (isset($middleware_obj["after"], $r[$i])) {
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] Middleware 存在后置事件,执行中 ...");
|
2020-09-29 15:07:43 +08:00
|
|
|
|
$r[$i]->{$middleware_obj["after"]}(...$params);
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] Middleware 后置事件执行完毕!");
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-01-02 13:15:50 +08:00
|
|
|
|
$this->status = self::STATUS_NORMAL;
|
|
|
|
|
|
return true;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
2021-01-02 13:15:50 +08:00
|
|
|
|
$this->status = self::STATUS_BEFORE_FAILED;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$q_o = ZMUtil::getModInstance($q_c);
|
2021-03-24 23:34:46 +08:00
|
|
|
|
$q_o->_running_annotation = $v;
|
2020-12-14 01:24:34 +08:00
|
|
|
|
if ($this->log) Console::verbose("[事件分发{$this->eid}] 正在执行方法 " . $q_c . "::" . $q_f . " ...");
|
2021-01-02 13:15:50 +08:00
|
|
|
|
$this->store = $q_o->$q_f(...$params);
|
|
|
|
|
|
$this->status = self::STATUS_NORMAL;
|
|
|
|
|
|
return true;
|
2020-09-29 15:07:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|