(PHP 8)
注解功能提供了代码中的声明部分都可以添加结构化、机器可读的元数据的能力, 注解的目标可以是类、方法、函数、参数、属性、类常量。 通过 反射 API 可在运行时获取注解所定义的元数据。 因此注解可以成为直接嵌入代码的配置式语言。
通过注解的使用,在应用中实现功能、使用功能可以相互解耦。 某种程度上讲,它可以和接口(interface)与其实现(implementation)相比较。 但接口与实现是代码相关的,注解则与声明额外信息和配置相关。 接口可以通过类来实现,而注解也可以声明到方法、函数、参数、属性、类常量中。 因此它们比接口更灵活。
     注解使用的一个简单例子:将接口(interface)的可选方法改用注解实现。
     我们假设接口 ActionHandler 代表了应用的一个操作:
     部分 action handler 的实现需要 setup,部分不需要。
     我们可以使用注解,而不用要求所有类必须实现 ActionHandler 
     接口并实现 setUp() 方法。
     因此带来一个好处——可以多次使用注解。
    
示例 #1 用注解实现接口的可选方法
<?php
interface ActionHandler
{
    public function execute();
}
#[Attribute]
class SetUp {}
class CopyFile implements ActionHandler
{
    public string $fileName;
    public string $targetDirectory;
    #[SetUp]
    public function fileExists()
    {
        if (!file_exists($this->fileName)) {
            throw new RuntimeException("File does not exist");
        }
    }
    #[SetUp]
    public function targetDirectoryExists()
    {
        if (!file_exists($this->targetDirectory)) {
            mkdir($this->targetDirectory);
        } elseif (!is_dir($this->targetDirectory)) {
            throw new RuntimeException("Target directory $this->targetDirectory is not a directory");
        }
    }
    public function execute()
    {
        copy($this->fileName, $this->targetDirectory . '/' . basename($this->fileName));
    }
}
function executeAction(ActionHandler $actionHandler)
{
    $reflection = new ReflectionObject($actionHandler);
    foreach ($reflection->getMethods() as $method) {
        $attributes = $method->getAttributes(SetUp::class);
        if (count($attributes) > 0) {
            $methodName = $method->getName();
            $actionHandler->$methodName();
        }
    }
    $actionHandler->execute();
}
$copyAction = new CopyFile();
$copyAction->fileName = "/tmp/foo.jpg";
$copyAction->targetDirectory = "/home/user";
executeAction($copyAction);