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
相关产品推荐
相关产品推荐

