THINKPHP框架增加注解功能

AOP(Aspect-Oriented Programming)是一种编程范式,旨在通过允许横切关注点的分离,提高模块化。它是一种面向对象编程的补充和完善,可以解决一些面向对象编程无法解决的问题。

在面向对象编程中,我们通常将问题拆分成一个个独立的对象,然后通过对象之间的交互来解决问题。然而,有时候我们需要在多个对象之间共享某些行为,例如日志记录、事务处理等。这些行为通常被称为横切关注点,因为它们跨越了多个对象,与业务逻辑无关,但却影响着业务逻辑的执行。

AOP允许我们将这些横切关注点从业务逻辑中分离出来,封装到独立的模块中,称为方面(Aspect)。方面可以定义在切入点和连接点上,切入点是指满足某些条件时执行方面代码的位置,连接点是指方面和目标代码之间的交互点。通过将横切关注点分离出来,我们可以更好地组织和管理代码,降低模块间的耦合度,提高代码的可重用性和可维护性。

在实现AOP时,通常需要使用专门的AOP框架。这些框架提供了切面编程的支持,包括切入点、连接点和方面等概念的实现。常见的AOP框架有Spring AOP、AspectJ等。

使用AOP可以带来很多好处。首先,它可以提高代码的可维护性和可重用性。通过将横切关注点分离出来,我们可以避免在多个地方重复编写相同的代码,同时也可以在不同的地方重用方面代码。其次,它可以降低模块间的耦合度。通过将横切关注点和业务逻辑分离出来,我们可以减少模块间的依赖关系,使模块更加独立和可替换。最后,它可以提高开发效率。通过将复杂的系统拆分成独立的方面,我们可以并行开发,提高开发效率和质量。

最近使用thinkphp 框架开发个项目,原框架没有提供日志记录功能,就着手使用php8 的注解功能 和AOP设计方法开发了日志记录功能。
下面简单介绍一下:
首先定义一个日志接口,这里定义了http请求处理后处理功能的接口方法:

namespace app;

/**
 * Interface ReqAfterInter
 * @package app
 */
interface ReqAfterInter
{
    public function handler($request,$response);
}

编写一个日志记录功能类,继承该接口,实现handler类

#[\Attribute(\Attribute::TARGET_METHOD)]
class OperLog implements ReqAfterInter {
    private $module = "";
    private $method = "";
    private $info   = "";

    /**
     * OperLog constructor.
     * @param string $method
     * @param string $module
     * @param string $info
     * @function :构造函数
     */
    public function __construct($method="",$module="",$info=""){

        $this->module = $module;
        $this->method = $method;
        $this->info = $info;
    }

    /**
     * @name:handler
     * @datetime:2023/12/5
     * @param $request
     * @param $response
     * @function:日志记录
     */
    public function handler($request,$response)
    {
        $userId = $request->jwtPayload->userId;
        $param = $request->param();
        $path = $request->pathInfo();
        $controller = $request->controller();
        $action = $request->action();

        try{
            $data=[
                'user_id' =>  $userId,
                'module'  =>  $module,
                'method'  =>  $method,
                'info'    =>  $info,
                'param'   =>  json_encode($param),
                'path_info'=> $path,
                'controller'=> $controller,
                'action' => $action
            ];

            Db::table("visit_log")->insert($data,true);

        }catch (\Exception $e)
        {
            Log::error("userId:".$userId." 日志数据insert错误:".$e->getMessage());
        }
    }

接下来,就是在tp框架下 如何在request 请求后处理调用注解标记的方法了,这里使用了框架的中间件功能,我们添加一个后置请求的中间件,在
middleware目录下添加RequestAfterAspect.php 类,这个类负责动态加载OperLog 类,使用反射机制执行OperLog类。同时为了实现可以动态配置和加载OperLog 类, 我们增加配置文件 annotation.php 内容如下:

<?php
/**
 * 返回需要使用的注解类
 */
return [
    app\annotation\OperLog::class,
];

RequestAfterAspect.php 主要完成过滤请求方法,加载配置的注解类,调用注解类里的handler方法,内容如下:

<?php


namespace app\middleware;


use think\facade\App;
use think\facade\Config;
use think\facade\Log;
use think\facade\Route;

class RequestAfterAspect
{
    private $annotations=[];

    private $afterAnnotations=[];

    private static $interfaceName = "ReqAfterInter";

    /**
     * RequestAfterAspect constructor.
     */
    public function __construct() {
        $dir = __DIR__;
        $path = realpath($dir.'/../annotation.php');//获取配置文件路径

        $this->annotations = include $path; // 加载注解类

        foreach($this->annotations as $after)
        {
            $interfaces = class_implements($after);

            foreach ($interfaces as $inters)
            {
                if(str_contains($inters,self::$interfaceName))
                {
                    array_push($this->afterAnnotations,$after);
                }

            }
        }
    }

    /**
     * @name:handle
     * @datetime:2023/11/30
     * @param $request
     * @param \Closure $next
     * @return mixed
     * @apiDescription
     */
    public function handle($request, \Closure $next)
    {
        $response = $next($request);

        if(empty($this->afterAnnotations))
        {
            return $response;
        }

        try{

            $pathInfo = $request->pathInfo();
            $action = $request->action();

            //转换路由
            $rule = Route::getRule($action);
            if(!empty($rule)){
                foreach ( $rule as $r)
                {
                    //Log::info($r->getName());
                    $pathInfo = $r->getName();
                }
            }
            if(!empty($rule)){
                foreach ( $rule as $r)
                {
                    $pathInfo = $r->getName();
                }
            }

            Log::info("path_info:".$pathInfo);
            $app = empty(Config::get('app.app_namespace'))?'app':Config::get('app.app_namespace');
            $nsController = Config::get('route.controller_layer');
            //处理多级控制器
            $pathInfo = str_replace('.','/',$pathInfo);

            $nss = explode('/',$pathInfo);
            $n = count($nss);
            if( $n > 1 )
            {

                $nameSpace = $app.'\\'.$nsController;
                foreach ($nss as $item)
                {
                    $nameSpace = $nameSpace."\\".$item;
                }

                $pos = strrpos($nameSpace, '\\');
                if ($pos !== false) {
                    $methodName = substr_replace($nameSpace, "::", $pos, strlen('\\'));

                    $refMethod = new \ReflectionMethod($methodName); 

                    foreach ($this->afterAnnotations  as $an)
                    {
                        $attributes = $refMethod->getAttributes($an);

                        foreach ($attributes as $attr)
                        {
                            $anInstance = $attr->newInstance();
                            $anInstance->handler($request,$response);
                        }

                    }
                }
            }
        } catch (\Exception $e)
        {
            Log::error("请求后处理错误:".$e->getMessage());
        } finally {
            return $response;
        }

    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

semicolon_helloword

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值