アトリビュートの概要

PHP のアトリビュートは、クラス、メソッド、関数、パラメータ、プロパティ、定数に、 構造化され、かつマシンが読み取り可能なメタデータを提供します。 これらは リフレクション API を介して実行時に検査でき、 コードを変更することなく動的な振る舞いを可能にします。 アトリビュートは、宣言的な方法でコードにメタデータの注釈を付ける方法を提供します。

アトリビュートは、機能の実装と利用を分離できるようにします。 インターフェイスがメソッドを強制することで構造を定義するのに対し、 アトリビュートはメソッド、関数、プロパティ、定数を含む、 複数の要素にわたってメタデータを提供します。 インターフェイスがメソッドの実装を強制するのとは異なり、 アトリビュートはコードの構造を変更することなく注釈を付けます。

アトリビュートは、強制された構造の代わりにメタデータを提供することで、 オプションのインターフェイスメソッドを補完または置き換えることができます。 アプリケーションでの操作を表す ActionHandler インターフェイスを考えてみましょう。 一部の実装ではセットアップ手順が必要な場合がありますが、必要ない場合もあります。 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);