kode/aop

基于 PHP 8.1+ 原生属性(Attribute)实现的轻量级、高性能、高扩展性 AOP(面向切面编程)组件

Maintainers

Package info

github.com/kodephp/aop

pkg:composer/kode/aop

Statistics

Installs: 17

Dependents: 1

Suggesters: 0

Stars: 1

Open Issues: 0

2.2.1 2026-03-17 06:52 UTC

This package is auto-updated.

Last update: 2026-03-17 06:52:59 UTC


README

PHP Version License

基于 PHP 8.1+ 原生属性(Attribute)实现的轻量级、高性能、高扩展性 AOP(面向切面编程)组件。

✨ 特性

  • 原生支持:基于 PHP 8.1+ 原生属性(Attribute)实现,IDE 友好
  • 轻量级:依赖 kode/attributes 包,无其他框架依赖
  • 高性能:使用缓存机制避免重复反射操作
  • 类型安全:充分利用 PHP 8.1+ 的类型系统,支持 readonly 属性
  • 扩展性强:支持前置通知(Before)、后置通知(After)、环绕通知(Around)
  • 优先级控制:支持通过 #[Priority] 注解控制切面执行顺序
  • 切入点表达式:支持通配符匹配,灵活定义切入点

📦 安装

composer require kode/aop

🚀 快速开始

1. 创建切面类

<?php

use Kode\Aop\Attribute\Aspect;
use Kode\Aop\Attribute\Before;
use Kode\Aop\Attribute\After;
use Kode\Aop\Attribute\Around;
use Kode\Aop\Runtime\JoinPoint;
use Kode\Aop\Runtime\ProceedingJoinPoint;

#[Aspect]
class LoggingAspect
{
    #[Before("execution(* App\Service\UserService->createUser(..))")]
    public function logBefore(JoinPoint $joinPoint): void
    {
        $args = $joinPoint->getArguments();
        echo "准备创建用户: " . json_encode($args[0]) . "\n";
    }

    #[After("execution(* App\Service\UserService->createUser(..))")]
    public function logAfter(JoinPoint $joinPoint): void
    {
        echo "用户创建操作已完成\n";
    }
}

2. 配置 AOP 内核

<?php

use Kode\Aop\Runtime\AspectKernel;

$kernel = AspectKernel::getInstance();
$kernel->registerAspect(new LoggingAspect());
$kernel->init();

$userService = $kernel->getProxy(UserService::class);

3. 使用代理对象

<?php

$result = $userService->createUser([
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

📖 详细文档

通知类型

Before(前置通知)

在目标方法执行前执行,可以修改方法参数或执行预处理逻辑。

#[Before("execution(* App\Service\*->*(..))")]
public function logBefore(JoinPoint $joinPoint): void
{
    $methodName = $joinPoint->getMethodName();
    $args = $joinPoint->getArguments();

    echo "方法 {$methodName} 即将执行\n";

    // 修改参数
    if (isset($args[0])) {
        $args[0] = trim($args[0]);
        $joinPoint->setArguments($args);
    }
}

After(后置通知)

在目标方法执行后执行(无论是否抛出异常),适用于资源清理、日志记录等场景。

#[After("execution(* App\Service\*->*(..))")]
public function logAfter(JoinPoint $joinPoint): void
{
    $result = $joinPoint->getResult();
    echo "方法执行完成,返回值: " . json_encode($result) . "\n";
}

Around(环绕通知)

环绕目标方法执行,可以完全控制方法的执行流程。

#[Around("execution(* App\Service\UserService->*(..))")]
public function transactional(ProceedingJoinPoint $joinPoint): mixed
{
    echo "开始事务\n";

    try {
        $result = $joinPoint->proceed();
        echo "提交事务\n";
        return $result;
    } catch (\Exception $e) {
        echo "回滚事务\n";
        throw $e;
    }
}

优先级控制

使用 #[Priority] 注解控制切面执行顺序,数字越小优先级越高。

#[Aspect]
class PriorityAspect
{
    #[Before("execution(* App\Service\*->*(..))")]
    #[Priority(Priority::HIGHEST)]  // 最先执行
    public function first(JoinPoint $joinPoint): void
    {
        echo "第一个执行\n";
    }

    #[Before("execution(* App\Service\*->*(..))")]
    #[Priority(100)]
    public function second(JoinPoint $joinPoint): void
    {
        echo "第二个执行\n";
    }
}

切入点表达式

支持的切入点表达式语法:

表达式 说明 示例
execution(* Class->method(..)) 执行方法 execution(* UserService->createUser(..))
execution(* Class->*(..)) 类的所有方法 execution(* UserService->*(..))
execution(* Namespace\*->*(..)) 命名空间下所有类的所有方法 execution(* App\Service\*->*(..))
within(Namespace\*) 命名空间下所有类 within(App\Controller\*)

通配符说明:

  • *:匹配任意数量的任意字符
  • ..:匹配任意参数列表
  • ?:匹配单个任意字符

JoinPoint API

JoinPoint 类提供了丰富的方法来获取方法调用的上下文信息:

$joinPoint->getClass();        // 获取目标类的反射对象
$joinPoint->getMethod();       // 获取目标方法的反射对象
$joinPoint->getThis();         // 获取目标对象实例
$joinPoint->getArguments();    // 获取方法参数
$joinPoint->setArguments([]);  // 设置方法参数
$joinPoint->getPointcut();     // 获取切入点表达式
$joinPoint->getResult();       // 获取返回值(After 通知)
$joinPoint->getMethodName();   // 获取方法名
$joinPoint->getClassName();    // 获取类名
$joinPoint->getArgument(0);    // 获取指定位置的参数

ProceedingJoinPoint API

ProceedingJoinPoint 继承自 JoinPoint,额外提供了控制原方法执行的能力:

$result = $joinPoint->proceed();                    // 使用原始参数执行
$result = $joinPoint->proceed(['newArg']);          // 使用新参数执行
$result = $joinPoint->proceedWithNamedParams([...]); // 使用命名参数执行
$closure = $joinPoint->getProceedClosure();         // 获取执行闭包

🏗️ 核心组件

src/
├── Attribute/               # 原生注解定义
│   ├── Aspect.php           # 切面标记
│   ├── Before.php           # 方法前执行
│   ├── After.php            # 方法后执行(无论异常)
│   ├── Around.php           # 环绕执行(可控制流程)
│   ├── Pointcut.php         # 切入点表达式
│   └── Priority.php         # 执行优先级
│
├── Contract/                # 接口契约
│   ├── AspectInterface.php
│   ├── JoinPointInterface.php
│   ├── ProceedingJoinPointInterface.php
│   └── AspectKernelInterface.php
│
├── Runtime/                 # 运行时核心
│   ├── JoinPoint.php        # 封装调用上下文
│   ├── ProceedingJoinPoint.php # Around 场景专用
│   └── AspectKernel.php     # 核心调度器
│
├── Reflection/              # 安全反射封装
│   ├── Reflector.php        # 安全获取类/方法/属性元数据
│   └── MetadataReader.php   # Attribute 元数据读取器
│
├── Exception/               # 自定义异常
│   └── AopException.php
│
└── Helper/                  # 工具函数
    └── Str.php              # 字符串匹配

🔧 框架集成

Laravel 集成

// app/Providers/AopServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Kode\Aop\Runtime\AspectKernel;

class AopServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(AspectKernel::class, function () {
            $kernel = AspectKernel::getInstance();
            $kernel->registerAspect(new \App\Aspects\LoggingAspect());
            $kernel->registerAspect(new \App\Aspects\TransactionAspect());
            $kernel->init();
            return $kernel;
        });
    }
}

Symfony 集成

// config/services.yaml
services:
    Kode\Aop\Runtime\AspectKernel:
        factory: ['@App\Aop\AspectKernelFactory', 'create']
        calls:
            - [init, []]

    App\Aop\AspectKernelFactory:
        class: App\Aop\AspectKernelFactory

Hyperf 集成

// config/autoload/dependencies.php
<?php

return [
    Kode\Aop\Runtime\AspectKernel::class => function () {
        $kernel = Kode\Aop\Runtime\AspectKernel::getInstance();
        $kernel->registerAspect(new \App\Aspect\LoggingAspect());
        $kernel->init();
        return $kernel;
    },
];

🧪 测试

运行测试:

composer test

运行代码覆盖率:

composer coverage

静态分析:

composer analyse

📋 系统要求

  • PHP >= 8.1
  • Composer >= 2.0
  • kode/attributes ^1.0

📄 许可证

Apache License 2.0

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📮 联系方式