You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP中编写自定义注解来修改类?以@Getters生成getter为例

在PHP中实现@Getters注解自动生成Getter方法

PHP本身没有原生注解系统,但可以通过解析类的文档注释(DocComment)结合反射机制,实现自动生成Getter方法的@Getters注解。下面分两种常见方案实现:

方案一:使用魔术方法动态处理Getter调用

这种方式无需修改类定义,通过__call魔术方法拦截不存在的Getter调用,直接返回对应私有属性的值。

1. 编写注解处理器类

class AnnotationProcessor {
    public static function instantiate($className, ...$args) {
        $reflection = new ReflectionClass($className);
        // 检查类文档注释是否包含@Getters
        $docComment = $reflection->getDocComment();
        if (strpos($docComment, '@Getters') === false) {
            return $reflection->newInstanceArgs($args);
        }

        // 创建继承原类的匿名类,通过__call处理Getter
        return new class(...$args) extends $className {
            public function __call($methodName, $arguments) {
                // 匹配get开头的方法名
                if (str_starts_with($methodName, 'get')) {
                    $propertyName = lcfirst(substr($methodName, 3));
                    if (property_exists($this, $propertyName)) {
                        return $this->$propertyName;
                    }
                }
                throw new BadMethodCallException("方法 {$methodName} 不存在");
            }
        };
    }
}

2. 使用@Getters注解并实例化类

/**
 * @Getters
 */
class Person {
    private $name;
    private $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
}

// 通过处理器实例化
$person = AnnotationProcessor::instantiate(Person::class, 'Alice', 30);
echo $person->getName(); // 输出 Alice
echo $person->getAge();  // 输出 30

方案二:类加载时预生成Getter方法

这种方式在类加载阶段动态修改类代码,生成真实的Getter方法,性能比魔术方法更好。

1. 注册自定义自动加载器

spl_autoload_register(function ($className) {
    $filePath = __DIR__ . '/' . str_replace('\\', '/', $className) . '.php';
    if (!file_exists($filePath)) return;

    $classContent = file_get_contents($filePath);
    // 检查类是否包含@Getters注解
    if (strpos($classContent, '@Getters') === false) {
        require $filePath;
        return;
    }

    // 提取类名和私有属性
    preg_match('/class (\w+)/', $classContent, $classMatch);
    $className = $classMatch[1];
    preg_match_all('/private \$(\w+);/', $classContent, $propertyMatches);
    $properties = $propertyMatches[1];

    // 生成Getter方法代码
    $getterCode = '';
    foreach ($properties as $prop) {
        $methodName = 'get' . ucfirst($prop);
        $getterCode .= "
    public function {$methodName}() {
        return \$this->{$prop};
    }
";
    }

    // 将Getter插入类定义
    $modifiedContent = preg_replace("/class {$className} {/", "class {$className} {{$getterCode}", $classContent);

    // 临时文件加载修改后的类
    $tempFile = tempnam(sys_get_temp_dir(), 'php_getter_');
    file_put_contents($tempFile, $modifiedContent);
    require $tempFile;
    unlink($tempFile);
});

2. 直接使用带@Getters注解的类

/**
 * @Getters
 */
class Person {
    private $name;
    private $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
}

// 直接实例化,自动拥有Getter方法
$person = new Person('Bob', 25);
echo $person->getName(); // 输出 Bob
echo $person->getAge();  // 输出 25

注意事项

  • 注解必须写在类的文档注释块(/** ... */)中,单行注释无法被解析。
  • 方案一实现简单,但每次调用Getter都会触发__call,性能略低;方案二生成真实的方法,性能更优,但需要处理类加载逻辑。
  • 如果需要复杂注解功能,可考虑使用成熟的第三方库,但简单场景下自己实现足够。

内容的提问来源于stack exchange,提问作者Mike U

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 04:09:58