You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony中如何修改代码读取控制器类的PHP Attribute属性?

从Symfony Annotation切换到PHP Attribute的修改方案

问题背景

现有一个已兼容PHP Attribute的Authenticaded类(原Annotation类改造而来),以及通过handleClassAnnotation方法读取类注解的逻辑,需要修改代码以支持读取PHP原生Attribute。

现有Authenticaded类代码

namespace App\Annotations;

use Attribute;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\ControllerEvent;

/**
 * @Annotation
 * @NamedArgumentConstructor
 * @Target({"CLASS", "METHOD"})
 */
#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Authenticaded extends _Annotation
{
    public function __construct()
    {
    }

    public function execute(
        ContainerInterface $container,
        ControllerEvent $event
    ) {
        // 业务逻辑
    }
}

现有读取Annotation的方法代码

private function handleClassAnnotation(
    ControllerEvent $event,
    \ReflectionClass $controller
) {
    foreach (
        [Authenticaded::class]
        as $class
    ) {
        $annotation = $this->reader->getClassAnnotation(
            $controller,
            $class
        );

        if ($annotation instanceof $class) {
            $continue = $annotation->execute(
                $this->container,
                $event
            );
            if (!$continue) {
                return false;
            }
        }
    }

    return true;
}

需要修改的内容

1. 清理Attribute类的旧Annotation注释

移除类上方的Doctrine Annotation注释块,因为已经通过#[Attribute]声明了PHP原生属性,旧注释不再需要:

// 移除以下注释块
/**
 * @Annotation
 * @NamedArgumentConstructor
 * @Target({"CLASS", "METHOD"})
 */

如果_Annotation基类是专为Doctrine Annotation设计的,可考虑移除继承(PHP Attribute不需要强制继承特定基类,除非你的自定义逻辑依赖它)。

2. 修改Attribute读取逻辑

原代码使用getClassAnnotation读取单个Doctrine Annotation,PHP Attribute支持重复声明(已设置IS_REPEATABLE),因此需要调整为遍历所有匹配的Attribute实例。

方案一:使用Symfony Reader兼容读取

如果继续使用Symfony的AnnotationReader(Symfony 5.4+已支持读取PHP Attribute),修改如下:

private function handleClassAnnotation(
    ControllerEvent $event,
    \ReflectionClass $controller
) {
    foreach ([Authenticaded::class] as $class) {
        // 获取类上所有匹配的Attribute
        $attributes = $this->reader->getClassAttributes($controller, $class);
        
        foreach ($attributes as $attribute) {
            $instance = $attribute->newInstance();
            $continue = $instance->execute($this->container, $event);
            if (!$continue) {
                return false;
            }
        }
    }

    return true;
}

方案二:使用PHP原生Reflection API

直接使用PHP原生反射读取Attribute,无需依赖Symfony的AnnotationReader:

private function handleClassAnnotation(
    ControllerEvent $event,
    \ReflectionClass $controller
) {
    foreach ([Authenticaded::class] as $class) {
        // 获取类上所有该类型的Attribute(支持继承匹配)
        $reflectionAttrs = $controller->getAttributes($class, \ReflectionAttribute::IS_INSTANCEOF);
        
        foreach ($reflectionAttrs as $attr) {
            $instance = $attr->newInstance();
            $continue = $instance->execute($this->container, $event);
            if (!$continue) {
                return false;
            }
        }
    }

    return true;
}

内容的提问来源于stack exchange,提问作者Vlad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:16:59