zhamao-framework/src/ZM/Annotation/AnnotationHandler.php
2022-12-20 23:19:55 +08:00

172 lines
5.6 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace ZM\Annotation;
use ZM\Exception\InterruptException;
/**
* 注解调用器,原 EventDispatcher
*/
class AnnotationHandler
{
public const STATUS_NORMAL = 0; // 正常结束
public const STATUS_INTERRUPTED = 1; // 被interrupt了不管在什么地方
public const STATUS_EXCEPTION = 2; // 执行过程中抛出了异常
public const STATUS_BEFORE_FAILED = 3; // 中间件HandleBefore返回了false所以不执行此方法
public const STATUS_RULE_FAILED = 4; // 判断事件执行的规则函数判定为false所以不执行此方法
private string|AnnotationBase $annotation_class;
/** @var callable */
private $rule_callback;
/** @var callable */
private $return_callback;
private int $status = self::STATUS_NORMAL;
private mixed $return_val;
/**
* 注解调用器构造函数
*
* @param string $annotation_class 注解类名
*/
public function __construct(string $annotation_class)
{
$this->annotation_class = $annotation_class;
logger()->debug('声明注解分发器 {annotation}', ['annotation' => $annotation_class]);
}
/**
* 立刻中断注解调用器执行
*
* @param null|mixed $return_var 中断执行返回值传入null则代表无返回值
* @throws InterruptException
*/
public static function interrupt(mixed $return_var = null)
{
throw new InterruptException($return_var);
}
/**
* 设置执行前判断注解是否应该被执行的检查回调函数
*
* @param callable $rule 回调函数
*/
public function setRuleCallback(callable $rule): AnnotationHandler
{
logger()->debug('注解调用器设置事件ruleFunc: {annotation}', ['annotation' => $this->annotation_class]);
$this->rule_callback = $rule;
return $this;
}
/**
* 设置成功执行后有返回值时执行的返回值后续逻辑回调函数
*
* @param callable $return 回调函数
*/
public function setReturnCallback(callable $return): AnnotationHandler
{
logger()->debug('注解调用器设置事件returnFunc: {annotation}', ['annotation' => $this->annotation_class]);
$this->return_callback = $return;
return $this;
}
/**
* 调用注册了该注解的所有函数们
* 此处会遍历所有注册了当前注解的函数,并支持中间件插入
*
* @param mixed ...$params 传入的参数们
* @throws \Throwable
*/
public function handleAll(mixed ...$params)
{
logger()->debug('开始分发注解 ' . $this->annotation_class);
try {
// 遍历注册的注解
foreach ((AnnotationMap::$_list[$this->annotation_class] ?? []) as $v) {
// 调用单个注解
$this->handle($v, $this->rule_callback, ...$params);
// 执行完毕后检查状态如果状态是规则判断或中间件before不通过则重置状态后继续执行别的注解函数
if ($this->status == self::STATUS_BEFORE_FAILED || $this->status == self::STATUS_RULE_FAILED) {
$this->status = self::STATUS_NORMAL;
continue;
}
// 如果执行完毕,且设置了返回值后续逻辑的回调函数,那么就调用返回值回调的逻辑
if (is_callable($this->return_callback) && $this->status === self::STATUS_NORMAL) {
($this->return_callback)($this->return_val);
}
}
} catch (InterruptException $e) {
// InterruptException 用于中断,这里必须 catch并标记状态
$this->return_val = $e->return_var;
$this->status = self::STATUS_INTERRUPTED;
} catch (\Throwable $e) {
// 其他类型的异常就顺势再抛出到外层,此层不做处理
$this->status = self::STATUS_EXCEPTION;
throw $e;
}
}
/**
* 调用单个注解
*
* @throws InterruptException
* @throws \Throwable
*/
public function handle(AnnotationBase $v, ?callable $rule_callback = null, ...$args): bool
{
// 由于3.0有额外的插件模式支持,所以注解就不再提供独立的闭包函数调用支持了
// 提取要调用的目标类和方法名称
$class = $v->class;
$target_method = $v->method;
if ($class !== '') {
$target_class = new $class();
$callback = [$target_class, $target_method];
} else {
$callback = $target_method;
}
// 先执行规则失败就返回false
if ($rule_callback !== null && !$rule_callback($v)) {
$this->status = self::STATUS_RULE_FAILED;
return false;
}
try {
$this->return_val = middleware()->process($callback, ...$args);
} catch (InterruptException $e) {
// 这里直接抛出这个异常的目的就是给上层handleAll()捕获
throw $e;
} catch (\Throwable $e) {
// 其余的异常就交给中间件的异常捕获器过一遍,没捕获的则继续抛出
$this->status = self::STATUS_EXCEPTION;
throw $e;
}
return true;
}
/**
* 获取分发的状态
*/
public function getStatus(): int
{
return $this->status;
}
/**
* 获取运行的返回值
*
* @return mixed
*/
public function getReturnVal()
{
return $this->return_val;
}
}