php8属性注解使用教程

简介

PHP 8 引入了 属性(Attributes)作为新的元数据机制,用于替代传统的 PHPDoc 注解,使得代码更具类型安全性和结构化。

基本语法

PHP 8 的属性(Attributes)使用 #[...] 语法表示,并可以用于类、方法、属性、参数、常量等。

定义属性

属性的本质是一个 PHP 类,通常以 Attribute 特性(flag)标记:

php 复制代码
#[Attribute] // 这是一个属性定义
class MyAttribute {
    public function __construct(public string $name) {}
}
不带 __construct() 的空类
php 复制代码
#[Attribute]
class SimpleAttribute {}

使用示例:

php 复制代码
#[SimpleAttribute]
class AnotherClass {}
使用属性

定义好 MyAttribute 之后,可以在类、方法、属性等地方使用:

php 复制代码
#[MyAttribute("Hello World")]
class MyClass {}

属性应用范围

PHP 8 允许在不同的地方使用属性,包括:

  • 类的属性

  • 类的方法

  • 方法参数

  • 常量

应用到类
php 复制代码
#[MyAttribute("This is a class")]
class DemoClass {}
应用到属性
php 复制代码
class User {
    #[MyAttribute("User ID")]
    public int $id;
}
应用到方法
php 复制代码
class MyController {
    #[MyAttribute("This is a method")]
    public function myMethod() {}
}
应用到方法参数
php 复制代码
class Test {
    public function greet(#[MyAttribute("Parameter annotation")] string $name) {
        echo "Hello, $name";
    }
}
应用到类常量
php 复制代码
class Status {
    #[MyAttribute("Status Active")]
    public const ACTIVE = 1;
}

解析属性

PHP 提供了 Reflection 机制来获取属性信息。

获取类的属性
php 复制代码
$reflection = new ReflectionClass(MyClass::class);
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->name; // 输出: Hello World
}
获取常量的属性
php 复制代码
$reflectionConstant = new ReflectionClassConstant(MyClass::class, 'MY_CONST');
$attributesConstant = $reflectionConstant->getAttributes();
foreach ($attributesConstant as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->name . "\n";
}
获取属性的属性
php 复制代码
$reflection = new ReflectionProperty(User::class, 'id');
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->name;
}
获取方法的属性
php 复制代码
$reflection = new ReflectionMethod(MyController::class, 'myMethod');
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->name;
}
获取方法参数的属性
php 复制代码
$reflectionMethod = new ReflectionMethod(MyClass::class, 'greet');
$parameters = $reflectionMethod->getParameters();
foreach ($parameters as $parameter) {
    $attributes = $parameter->getAttributes();
    foreach ($attributes as $attribute) {
        $instance = $attribute->newInstance();
        echo $instance->name . "\n";
    }
}

高级用法

指定属性的适用范围

PHP 提供了 Attribute::TARGET_* 来限定属性可以应用的位置。

php 复制代码
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class OnlyForClassAndMethod {}

这样,OnlyForClassAndMethod 只能用于类和方法,如果用于属性,则会报错。

应用同一个属性多次
php 复制代码
#[MyAttribute("First"), MyAttribute("Second")]
class Example {}

注意:同一个属性应用了多次,则需要属性本身支持 Attribute::IS_REPEATABLE 可重复应用的目标

同时应用多个不同的属性

PHP 8 允许在同一元素(类、方法、属性等)上使用多个不同的属性,只需使用 多个 #[...] 语法 或 在 #[...] 内逗号分隔多个属性。

  • 多个 #[...] 语法
php 复制代码
#[Attribute]
class FirstAttribute {}

#[Attribute]
class SecondAttribute {}

#[FirstAttribute]
#[SecondAttribute]
class MultiAttributeClass {}
  • 在同一个 #[...] 里使用逗号分隔
php 复制代码
#[FirstAttribute, SecondAttribute]
class AnotherMultiAttributeClass {}
带参数的属性
php 复制代码
#[Attribute]
class Route {
    public function __construct(public string $path, public string $method = "GET") {}
}

#[Route("/home", "GET")]
class HomeController {}

解析:

php 复制代码
$reflection = new ReflectionClass(HomeController::class);
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo "Path: " . $instance->path . ", Method: " . $instance->method;
}
同时使用带参数和不带参数的属性
php 复制代码
#[Attribute]
class Role {
    public function __construct(public string $roleName) {}
}

#[Attribute]
class Loggable {}

#[Role("Admin"), Loggable]
class UserService {}

解析:

php 复制代码
$reflection = new ReflectionClass(UserService::class);
$attributes = $reflection->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    if ($instance instanceof Role) {
        echo "Role: " . $instance->roleName . PHP_EOL;
    } else {
        echo "Attribute: " . $attribute->getName() . PHP_EOL;
    }
}

输出:

php 复制代码
Role: Admin
Attribute: Loggable

实际应用场景

路由映射(模拟 Laravel 路由)
php 复制代码
#[Attribute]
class Route {
    public function __construct(public string $path, public string $method = "GET") {}
}

class MyController {
    #[Route('/users', 'GET')]
    public function getUsers() {}

    #[Route('/users', 'POST')]
    public function createUser() {}
}

// 解析控制器的方法路由
$reflection = new ReflectionClass(MyController::class);
foreach ($reflection->getMethods() as $method) {
    foreach ($method->getAttributes(Route::class) as $attribute) {
        $route = $attribute->newInstance();
        echo "Method: {$route->method}, Path: {$route->path}" . PHP_EOL;
    }
}

输出:

php 复制代码
Method: GET, Path: /users
Method: POST, Path: /users
相关推荐
r***F26211 分钟前
【漏洞复现】CVE-2019-11043(PHP远程代码执行漏洞)信息安全论文_含漏洞复现完整过程_含Linux环境go语言编译环境安装
linux·golang·php
SEO_juper2 小时前
别再纠结LLMs.txt了!它背后的真相与最佳使用场景,一文讲透。
开发语言·ai·php·数字营销
p***c9493 小时前
PHP在电商中的电商系统
开发语言·php
阿星智力囊3 小时前
Thinkphp6+nginx环境报错信息不显示,接口直接报500和CORS跨域(错误的引导方向),真坑啊
运维·nginx·php·thinkphp6
Xudde.6 小时前
Quick2靶机渗透
笔记·学习·安全·web安全·php
F***c3257 小时前
PHP在微服务中的分布式跟踪
分布式·微服务·php
chxii8 小时前
PHP 配置全解析:Apache vs Nginx 的线程安全差异与 Windows 实战指南
运维·php
用户607320369459 小时前
PHP cURL 接口调不通?最全故障排查流程来了(新手必收藏)
php
q***721910 小时前
PHP使用Redis实战实录2:Redis扩展方法和PHP连接Redis的多种方案
开发语言·redis·php
非凡的世界14 小时前
为什么我和越来越多的PHP程序员,选择了 Webman ?
开发语言·php·workman·webman