Attributes 개요

(PHP 8)

Attributes는 코드의 선언에 대해 구조화되고 기계가 읽을 수 있는 메타데이터 정보를 추가하는 기능을 제공합니다. 클래스, 메서드, 함수, 매개변수, 속성(properties) 및 클래스 상수는 attribute의 대상이 될 수 있습니다. 그런 다음 attribute로 정의된 메타데이터는 Reflection API를 사용하여 런타임에 검사할 수 있습니다. 따라서 Attributes는 코드에 직접 포함된 구성 언어로 생각할 수 있습니다.

Attributes을 사용하면 기능의 일반적인 구현과 애플리케이션에서의 구체적인 사용을 분리할 수 있습니다. 어떤 면에서는 인터페이스 및 해당 구현과 비슷합니다. 그러나 인터페이스와 구현이 코드에 관한 것이라면 Attributes는 추가 정보와 구성에 주석을 달기 위한 것입니다. 인터페이스는 클래스로 구현될 수 있지만 Attributes는 메서드, 함수, 매개변수, 속성(properties) 및 클래스 상수에서도 선언될 수 있습니다. 따라서 인터페이스보다 유연합니다.

Attribute 사용의 간단한 예는 Attributes을 사용하는 선택적 메서드가 있는 인터페이스를 변환하는 것입니다. 액션 핸들러의 일부 구현에는 설정이 필요하고 다른 구현에는 필요하지 않은 애플리케이션의 작업을 나타내는 ActionHandler 인터페이스를 가정해 보겠습니다. 메서드 setUp()을 구현하기 위해 ActionHandler를 구현하는 모든 클래스를 요구하는 대신 Attribute을 사용할 수 있습니다. 이 접근 방식의 한 가지 이점은 Attribute을 여러 번 사용할 수 있다는 것입니다.

예제 #1 Attributes을 사용하여 인터페이스의 선택적 메서드 구현

                  
<?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);