アトリビュートの概要

(PHP 8)

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