网站首页 > 知识剖析 正文
简介
PHP 8 引入了 属性(Attributes)作为新的元数据机制,用于替代传统的 PHPDoc 注解,使得代码更具类型安全性和结构化。
基本语法
PHP 8 的属性(Attributes)使用 #[...] 语法表示,并可以用于类、方法、属性、参数、常量等。
定义属性
属性的本质是一个 PHP 类,通常以 Attribute 特性(flag)标记:
#[Attribute] // 这是一个属性定义
class MyAttribute {
public function __construct(public string $name) {}
}
不带 __construct() 的空类
#[Attribute]
class SimpleAttribute {}
使用示例:
#[SimpleAttribute]
class AnotherClass {}
使用属性
定义好 MyAttribute 之后,可以在类、方法、属性等地方使用:
#[MyAttribute("Hello World")]
class MyClass {}
属性应用范围
PHP 8 允许在不同的地方使用属性,包括:
- 类
- 类的属性
- 类的方法
- 方法参数
- 常量
应用到类
#[MyAttribute("This is a class")]
class DemoClass {}
应用到属性
class User {
#[MyAttribute("User ID")]
public int $id;
}
应用到方法
class MyController {
#[MyAttribute("This is a method")]
public function myMethod() {}
}
应用到方法参数
class Test {
public function greet(#[MyAttribute("Parameter annotation")] string $name) {
echo "Hello, $name";
}
}
应用到类常量
class Status {
#[MyAttribute("Status Active")]
public const ACTIVE = 1;
}
解析属性
PHP 提供了 Reflection 机制来获取属性信息。
获取类的属性
$reflection = new ReflectionClass(MyClass::class);
$attributes = $reflection->getAttributes();
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
echo $instance->name; // 输出: Hello World
}
获取常量的属性
$reflectionConstant = new ReflectionClassConstant(MyClass::class, 'MY_CONST');
$attributesConstant = $reflectionConstant->getAttributes();
foreach ($attributesConstant as $attribute) {
$instance = $attribute->newInstance();
echo $instance->name . "\n";
}
获取属性的属性
$reflection = new ReflectionProperty(User::class, 'id');
$attributes = $reflection->getAttributes();
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
echo $instance->name;
}
获取方法的属性
$reflection = new ReflectionMethod(MyController::class, 'myMethod');
$attributes = $reflection->getAttributes();
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
echo $instance->name;
}
获取方法参数的属性
$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_* 来限定属性可以应用的位置。
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class OnlyForClassAndMethod {}
这样,OnlyForClassAndMethod 只能用于类和方法,如果用于属性,则会报错。
应用同一个属性多次
#[MyAttribute("First"), MyAttribute("Second")]
class Example {}
注意:同一个属性应用了多次,则需要属性本身支持 Attribute::IS_REPEATABLE 可重复应用的目标
同时应用多个不同的属性
PHP 8 允许在同一元素(类、方法、属性等)上使用多个不同的属性,只需使用 多个 #[...] 语法 或 在 #[...] 内逗号分隔多个属性。
- 多个 #[...] 语法
#[Attribute]
class FirstAttribute {}
#[Attribute]
class SecondAttribute {}
#[FirstAttribute]
#[SecondAttribute]
class MultiAttributeClass {}
- 在同一个 #[...] 里使用逗号分隔
#[FirstAttribute, SecondAttribute]
class AnotherMultiAttributeClass {}
带参数的属性
#[Attribute]
class Route {
public function __construct(public string $path, public string $method = "GET") {}
}
#[Route("/home", "GET")]
class HomeController {}
解析:
$reflection = new ReflectionClass(HomeController::class);
$attributes = $reflection->getAttributes();
foreach ($attributes as $attribute) {
$instance = $attribute->newInstance();
echo "Path: " . $instance->path . ", Method: " . $instance->method;
}
同时使用带参数和不带参数的属性
#[Attribute]
class Role {
public function __construct(public string $roleName) {}
}
#[Attribute]
class Loggable {}
#[Role("Admin"), Loggable]
class UserService {}
解析:
$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;
}
}
输出:
Role: Admin
Attribute: Loggable
实际应用场景
路由映射(模拟 Laravel 路由)
#[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;
}
}
输出:
Method: GET, Path: /users
Method: POST, Path: /users
- 上一篇: PHP 中不可能存在的 XXE
- 下一篇: 后端开发干货:PHP源码阅读技巧
猜你喜欢
- 2025-04-26 workerman 自定义的协议如何解决粘包拆包
- 2025-04-26 Everything 在应急响应中的使用
- 2025-04-26 后端开发干货:PHP源码阅读技巧
- 2025-04-26 PHP 中不可能存在的 XXE
- 2025-04-26 PHP-FPM 学习记录
- 2025-04-26 【玩法悉知】:领地战玩法全解析!
- 2025-04-26 PHP实现URL编码、Base64编码、MD5编码的方法
- 2025-04-26 PHP中<textarea>里的内容保存MYSQL后页面输出不换行的解决方法
- 2025-04-26 详解php-fmp.conf和php.ini文件
- 2025-04-26 六种流行语言(C、C++、Python、JavaScript、PHP、Java)对比
- 04-26workerman 自定义的协议如何解决粘包拆包
- 04-26Everything 在应急响应中的使用
- 04-26后端开发干货:PHP源码阅读技巧
- 04-26php8属性注解使用教程
- 04-26PHP 中不可能存在的 XXE
- 04-26PHP-FPM 学习记录
- 04-26【玩法悉知】:领地战玩法全解析!
- 04-26PHP实现URL编码、Base64编码、MD5编码的方法
- 最近发表
- 标签列表
-
- xml (46)
- css animation (57)
- array_slice (60)
- htmlspecialchars (54)
- position: absolute (54)
- datediff函数 (47)
- array_pop (49)
- jsmap (52)
- toggleclass (43)
- console.time (63)
- .sql (41)
- ahref (40)
- js json.parse (59)
- html复选框 (60)
- css 透明 (44)
- css 颜色 (47)
- php replace (41)
- css nth-child (48)
- min-height (40)
- xml schema (44)
- css 最后一个元素 (46)
- location.origin (44)
- table border (49)
- html tr (40)
- video controls (49)