PHP code example of x2nx / webman-aop

1. Go to this page and download the library: Download x2nx/webman-aop library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

x2nx / webman-aop example snippets




return [
    // 是否启用 AOP
    'enable' => true,
    
    // 扫描目录
    'scan_dirs' => [
        app_path(),
    ],
    
    // 排除目录
    'exclude_dirs' => [
        'vendor',
        'runtime',
        'config',
        'public',
    ],
];



namespace app\controller\v1\customer;

use X2nx\WebmanAop\Attribute\Aspect;
use X2nx\WebmanAop\Aspect\LogAspect;

class IndexController
{
    #[Aspect(LogAspect::class)]
    public function index()
    {
        // 方法逻辑
    }
}



namespace app\controller\v1\customer;

use X2nx\WebmanAop\Attribute\Aspect;
use X2nx\WebmanAop\Aspect\LogAspect;

#[Aspect(LogAspect::class)]
class IndexController
{
    // 所有公共方法都会应用 LogAspect
    public function index() {}
    public function detail() {}
}



use X2nx\WebmanAop\Attribute\Aspect;
use X2nx\WebmanAop\Aspect\LogAspect;
use app\aspect\CacheAspect;

#[Aspect(LogAspect::class, [], 100)]      // 优先级 100,后执行
#[Aspect(CacheAspect::class, [], 50)]    // 优先级 50,先执行
class IndexController
{
    // 切面执行顺序:CacheAspect -> LogAspect -> 原方法
}



namespace app\aspect;

use X2nx\WebmanAop\Contract\AspectInterface;
use X2nx\WebmanAop\JoinPoint;

class CacheAspect implements AspectInterface
{
    public function before(JoinPoint $joinPoint): void
    {
        // 前置通知:在目标方法执行前执行
    }

    public function after(JoinPoint $joinPoint): void
    {
        // 后置通知:在目标方法执行后执行(无论是否抛出异常)
    }

    public function around(JoinPoint $joinPoint, callable $proceed): mixed
    {
        // 环绕通知:可以控制目标方法的执行
        // 可以修改参数、返回值,或决定是否执行目标方法
        return $proceed();
    }

    public function afterReturning(JoinPoint $joinPoint, mixed $result): void
    {
        // 返回后通知:在目标方法正常返回后执行
    }

    public function afterThrowing(JoinPoint $joinPoint, \Throwable $exception): void
    {
        // 异常后通知:在目标方法抛出异常后执行
    }
}



namespace app\aspect;

use X2nx\WebmanAop\Contract\AbstractAspect;
use X2nx\WebmanAop\JoinPoint;
use support\Cache;

class CacheAspect extends AbstractAspect
{
    public function before(JoinPoint $joinPoint): void
    {
        // 前置:检查缓存
        $cacheKey = $this->getCacheKey($joinPoint);
        if ($cached = Cache::get($cacheKey)) {
            $joinPoint->setReturnValue($cached);
            $joinPoint->setData('from_cache', true);
        }
    }

    public function around(JoinPoint $joinPoint, callable $proceed): mixed
    {
        // 如果从缓存获取,直接返回
        if ($joinPoint->getData('from_cache')) {
            return $joinPoint->getReturnValue();
        }

        // 执行目标方法
        $result = $proceed();

        // 保存缓存
        $cacheKey = $this->getCacheKey($joinPoint);
        Cache::set($cacheKey, $result, 3600);

        return $result;
    }

    protected function getCacheKey(JoinPoint $joinPoint): string
    {
        $method = $joinPoint->getFullMethodName();
        $args = $joinPoint->getArgs();
        return 'aop_cache:' . md5($method . serialize($args));
    }
}

public function before(JoinPoint $joinPoint): void
{
    // 在目标方法执行前执行
    Log::info('Before method execution');
}

public function after(JoinPoint $joinPoint): void
{
    // 无论是否抛出异常,都会执行
    Log::info('After method execution');
}

public function around(JoinPoint $joinPoint, callable $proceed): mixed
{
    // 前置逻辑
    $this->beforeLogic();
    
    // 执行目标方法(可以修改参数)
    $result = $proceed();
    
    // 后置逻辑(可以修改返回值)
    return $this->afterLogic($result);
}

public function afterReturning(JoinPoint $joinPoint, mixed $result): void
{
    // 只在正常返回时执行
    Log::info('Method returned', ['result' => $result]);
}

public function afterThrowing(JoinPoint $joinPoint, \Throwable $exception): void
{
    // 只在抛出异常时执行
    Log::error('Method threw exception', [
        'exception' => get_class($exception),
        'message' => $exception->getMessage()
    ]);
}

// 获取目标对象
$target = $joinPoint->getTarget();

// 获取类名和方法名
$className = $joinPoint->getClassName();
$methodName = $joinPoint->getMethodName();
$fullMethodName = $joinPoint->getFullMethodName();

// 获取和设置参数
$args = $joinPoint->getArgs();
$joinPoint->setArgs($newArgs);
$arg = $joinPoint->getArg(0);
$joinPoint->setArg(0, $value);

// 执行原方法
$result = $joinPoint->proceed();

// 获取返回值和异常
$returnValue = $joinPoint->getReturnValue();
$exception = $joinPoint->getException();

// 数据存储(用于切面之间传递数据)
$joinPoint->setData('key', $value);
$value = $joinPoint->getData('key', $default);
$allData = $joinPoint->getAllData();



namespace app\aspect;

use X2nx\WebmanAop\Contract\AbstractAspect;
use X2nx\WebmanAop\JoinPoint;
use support\Cache;

class CacheAspect extends AbstractAspect
{
    public function before(JoinPoint $joinPoint): void
    {
        $cacheKey = $this->getCacheKey($joinPoint);
        if ($cached = Cache::get($cacheKey)) {
            $joinPoint->setReturnValue($cached);
            $joinPoint->setData('from_cache', true);
        }
    }

    public function around(JoinPoint $joinPoint, callable $proceed): mixed
    {
        if ($joinPoint->getData('from_cache')) {
            return $joinPoint->getReturnValue();
        }

        $result = $proceed();
        
        $cacheKey = $this->getCacheKey($joinPoint);
        Cache::set($cacheKey, $result, 3600);
        
        return $result;
    }

    protected function getCacheKey(JoinPoint $joinPoint): string
    {
        return 'aop_cache:' . md5($joinPoint->getFullMethodName() . serialize($joinPoint->getArgs()));
    }
}



namespace app\aspect;

use X2nx\WebmanAop\Contract\AbstractAspect;
use X2nx\WebmanAop\JoinPoint;
use support\Db;

class TransactionAspect extends AbstractAspect
{
    public function around(JoinPoint $joinPoint, callable $proceed): mixed
    {
        Db::beginTransaction();
        
        try {
            $result = $proceed();
            Db::commit();
            return $result;
        } catch (\Throwable $e) {
            Db::rollBack();
            throw $e;
        }
    }
}