本文目录导读:

在 PHP 中,“注解转属性”通常有两种含义:
- 将 PHPDoc 注解(如
@param、@return)解析并转换为类属性或对象属性 - 将 PHP 8 原生注解(Attributes)提取并应用到类/方法/属性的元数据中
下面分别给出演示:
将 PHPDoc 注解转换为属性
适用于需要兼容旧版 PHP 或需要手动解析 PHPDoc 的场景。
示例代码
<?php
use ReflectionClass;
use ReflectionProperty;
/**
* @author John
* @version 1.0.0
*/
class User
{
/**
* @var int
* @example 1001
*/
public int $id;
/**
* @var string
* @length 50
*/
public string $name;
}
/**
* 解析 PHPDoc 注解并填充到对象属性上
*/
function parseDocToProperty(string $className): object
{
$ref = new ReflectionClass($className);
$instance = $ref->newInstanceWithoutConstructor();
// 获取类级注解(可选)
$classDoc = $ref->getDocComment();
preg_match('/@author\s+(\w+)/', $classDoc, $authorMatch);
if (!empty($authorMatch[1])) {
$instance->author = $authorMatch[1]; // 动态添加属性
}
// 遍历所有属性,解析属性级注解
foreach ($ref->getProperties(ReflectionProperty::IS_PUBLIC) as $prop) {
$doc = $prop->getDocComment();
if (!$doc) continue;
// 提取 @var 类型
preg_match('/@var\s+(\S+)/', $doc, $varMatch);
if (!empty($varMatch[1])) {
// 将类型映射到属性上(可以用动态属性存储)
$instance->{$prop->getName() . '_type'} = $varMatch[1];
}
// 提取自定义注解如 @example
preg_match('/@example\s+(.*)/', $doc, $exampleMatch);
if (!empty($exampleMatch[1])) {
$instance->{$prop->getName() . '_example'} = trim($exampleMatch[1]);
}
// 提取 @length
preg_match('/@length\s+(\d+)/', $doc, $lengthMatch);
if (!empty($lengthMatch[1])) {
$instance->{$prop->getName() . '_length'} = (int)$lengthMatch[1];
}
}
return $instance;
}
$user = parseDocToProperty(User::class);
print_r($user);
输出
User Object
(
[id] =>
[name] =>
[author] => John
[id_type] => int
[id_example] => 1001
[name_type] => string
[name_length] => 50
)
PHP 8 原生注解(Attributes)转为属性
PHP 8+ 推荐使用原生 #[Attribute] 语法,解析更方便。
示例代码
<?php
use Attribute;
use ReflectionClass;
use ReflectionProperty;
// 1. 定义注解类
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)]
class Author
{
public function __construct(public string $name) {}
}
#[Attribute(Attribute::TARGET_PROPERTY)]
class Length
{
public function __construct(public int $max) {}
}
// 2. 使用注解
#[Author("John")]
class User
{
#[Length(50)]
public string $name;
#[Author("Admin")]
public int $id;
}
// 3. 解析注解并赋值到属性
function attributesToProperties(string $className): object
{
$ref = new ReflectionClass($className);
$instance = $ref->newInstanceWithoutConstructor();
// 处理类级注解
$classAttrs = $ref->getAttributes(Author::class);
if (!empty($classAttrs)) {
$author = $classAttrs[0]->newInstance();
$instance->classAuthor = $author->name; // 动态添加属性
}
// 处理属性级注解
foreach ($ref->getProperties() as $prop) {
$attrName = $prop->getName() . 'Meta'; // 存储元数据的属性名
// 获取 Length 注解
$lengthAttrs = $prop->getAttributes(Length::class);
if (!empty($lengthAttrs)) {
$length = $lengthAttrs[0]->newInstance();
$instance->{$attrName}['length'] = $length->max;
}
// 获取 Author 注解
$authorAttrs = $prop->getAttributes(Author::class);
if (!empty($authorAttrs)) {
$author = $authorAttrs[0]->newInstance();
$instance->{$attrName}['author'] = $author->name;
}
}
return $instance;
}
$user = attributesToProperties(User::class);
print_r($user);
输出
User Object
(
[name] =>
[id] =>
[classAuthor] => John
[nameMeta] => Array ( [length] => 50 )
[idMeta] => Array ( [author] => Admin )
)
使用第三方库(推荐生产环境)
| 库 | 说明 |
|---|---|
| doctrine/annotations | 解析 PHPDoc 注解(PHP 7+) |
| phpdocumentor/reflection-docblock | 灵活解析 PHPDoc |
| spiral/attributes | 统一处理 PHP 8 Attributes 和 PHPDoc |
示例(doctrine/annotations)
use Doctrine\Common\Annotations\AnnotationReader; $reader = new AnnotationReader(); $ref = new ReflectionClass(User::class); $classAnnotations = $reader->getClassAnnotations($ref); // 直接获得注解对象数组
选择哪种方式?
| 场景 | 推荐方式 |
|---|---|
| PHP 8.0+ 项目 | 使用原生 #[Attribute] + ReflectionAttribute |
| 兼容 PHP 7.x | 使用 Doctrine Annotations 或手动解析 PHPDoc |
| 简单的元数据提取 | 正则解析 PHPDoc 快速实现 |
| 框架/工具开发 | 优先使用原生 Attributes,保证性能与 IDE 支持 |
需要更具体的代码(如遍历所有注解、支持嵌套注解)可以告诉我你的 PHP 版本和具体需求。