PHP 怎么PHP 注解转属性

wen PHP项目 3

本文目录导读:

PHP 怎么PHP 注解转属性

  1. 将 PHPDoc 注解转换为属性
  2. PHP 8 原生注解(Attributes)转为属性
  3. 使用第三方库(推荐生产环境)
  4. 总结:选择哪种方式?

在 PHP 中,“注解转属性”通常有两种含义:

  1. 将 PHPDoc 注解(如 @param@return)解析并转换为类属性或对象属性
  2. 将 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 版本和具体需求。

抱歉,评论功能暂时关闭!