本文目录导读:

在 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 版本和具体需求。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播