Hyperf 的AOP 面向切面编程实战

概念

AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过动态代理等技术实现程序功能的统一维护的一种技术。AOP 是 OOP 的延续,也是 Hyperf 中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

用通俗的话来讲,就是在 Hyperf 里可以通过 切面(Aspect) 介入到任意类的任意方法的执行流程中去,从而改变或加强原方法的功能,这就是 AOP。

注意这里所指的任意类并不是完全意义上的所有类,在 Hyperf 启动初期用于实现 AOP 功能的类自身不能被切入。

介绍

相对于其它框架实现的 AOP 功能的使用方式,我们进一步简化了该功能的使用不做过细的划分,仅存在 环绕(Around) 一种通用的形式:

  • 切面(Aspect) 为对流程织入的定义类,包括要介入的目标,以及实现对原方法的修改加强处理
  • 代理类(ProxyClass) ,每个被介入的目标类最终都会生成一个代理类,来达到执行 切面(Aspect) 方法的目的

AOP的使用

示例如下,定义一个切面 /App/Aspect/TestAspect.php 切入到用户注册UserController/register 方法中,实现注册之前和注册完成后的逻辑控制:

(每个切面必须定义 @Aspect 注解或在 config/autoload/aspects.php 内进行配置)

<?php
namespace App\Aspect;
use App\Controller\UserController;
//use App\Annotation\SomeAnnotation;
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
/**
 * @Aspect
 */
class TestAspect extends AbstractAspect
{
    //要切入的类或Trait或方法,可以多个
    public $classes = [
        //以下三种方式示例效果相同
        'App\Controller\UserController::register', //切入具体某个方法
//        UserController::class, //切入类
//        'App\Controller\UserController::*ter', //通过*模糊匹配
    ];

    //要切入的注解,具体切入的还是使用了这些注解的类,仅可切入类注解和类方法注解
    public $annotations = [
//        SomeAnnotation::class,
    ];

    //切面切入后执行的控制逻辑
    public function process(ProceedingJoinPoint $proceedingJoinPoint)
    {
        //示例:调用前进行某些处理
        echo date("H:i:s",time()) . ":切入注册方法\n";

        //示例:调用后进行某些处理
        $result = $proceedingJoinPoint->process(); //通过连接点的process()方法获得调用原方法结果
        echo date("H:i:s",time()) . ":注册成功uid:". $result["uid"] . "\n";
    }
}

用户注册:

<?php

declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\Di\Annotation\Inject;
/**
 * @AutoController()
 */
class UserController
{
    //注册
    public function register()
    {
        echo date("H:i:s",time()) . ":开始注册\n";
        sleep(1);
        echo date("H:i:s",time()) . ":完成注册\n";

        //用户信息
        $userInfo = ['uid' => 666, 'mobile'=> 18888888888];

        return $userInfo;
    }
}

调用结果如下:

切入注册方法

开始注册

完成注册

注册成功uid:666

微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?