PHP8の Attribute 、公式の説明読んでも全然頭に入ってきません

https://www.php.net/manual/ja/language.attributes.overview.php

[PHPUnit11 の Attribute](https://qiita.com/kazumacchi/items/eb6a3059f730a9e6e3d6) は記事書いて何となく理解出来たというか、アノテーションとほとんど変わらないような気がしますが、公式の説明だとアノテーションとは全然違うような印象

これを初見で理解できる人間が存在するんでしょうか…するんでしょうね

一応この行を書いている時点では理解していませんが、調べながらメモしていきます
記事を公開する頃には理解しているハズ…

# サンプルコード

## Attribute は通常クラスに[Attribute]を記述することで定義する

```php
namespace App\Attribute;

// コレ。TestAttribute という名称の Attribute が定義される。
#[Attribute]
class TestAttribute
{
    /**
     * @param  string  $message
     */
    public function __construct(
        public string $message
    ) {
    }
}
```

## 定義した Attribute を利用したいクラスに設定

```php
use App\Attribute\TestAttribute;

// コレ。定義済の Attribute名（※クラス名）を記述する
#[TestAttribute(message: "アトリビュート利用テスト")]
class TestClass
{
}
```

設定した Attribute の引数が、対象 Attribute のコンストラクタ引数として渡される模様

## 設定した Attribute を、ReflectionClass クラスを利用して取得する

```php
$reflectionClass = new ReflectionClass(TestClass::class);
$attributes = $reflectionClass->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->message; // 「アトリビュート利用テスト」が出力される
}
```


$attribute->newInstance() 以降の処理イメージとしてはこんな感じ

```php
$instance = new TestAttribute($message = 'アトリビュート利用テスト');
echo $instance->message;
```

## Attribute は複数設定できる

:::note info
TestAttribute の定義は省略します
:::

QuizAttribute を定義

```php
#[Attribute]
class QuizAttribute
{
    /**
     * @param  int  $value
     */
    public function __construct(
        public int $value
    ) {
    }
}
```

TestAttribute と QuizAttribute を設定することが出来る

```php
use App\Attribute\TestAttribute;
use App\Attribute\QuizAttribute;

#[TestAttribute(message: "アトリビュート利用テスト")]
#[QuizAttribute(value: 1)]
class TestClass
{
}
```

## Attribute はクラスそのものだけではなく、 メソッド、パラメータ、プロパティ、定数に対しても設定できる

## クラスメソッドに Attribute 

:::note info
TestAttribute の定義は省略します
:::

該当メソッドに対して、定義した TestAttribute を設定

```php
use App\Attribute\TestAttribute;

class TestClass
{
    #[TestAttribute(message: "アトリビュート利用テスト")]
    public function testMethod()
    {
        // 略
    }
}
```

ReflectionMethod クラスを利用して該当メソッドの Attribute を取得

```php
$reflectionMethod = new ReflectionMethod(TestClass::class, 'testMethod');
$attributes = $reflectionMethod->getAttributes();
foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->message; // 「アトリビュート利用テスト」が出力される
}
```

### パラメータに Attribute

DescriptionAttribute を定義

```php
#[Attribute]
class DescriptionAttribute
{
    /**
     * @param  string  $description
     */
    public function __construct(
        public string $description
    ) {
    }
}
```

該当パラメータに対して、定義した DescriptionAttribute を設定

```php
<?php
use App\Attribute\TestAttribute;

class TestClass
{
    public function testMethod(
        #[DescriptionAttribute(description: "パラメータの説明だよ")]
        int $value
    ) {
        // 略
    }
}
```

ReflectionMethod クラスの getParameters() メソッドを利用して該当パラメータの Attribute を取得

```php
$reflectionMethod = new ReflectionMethod(TestClass::class, 'testMethod');
$reflectionParameter = $reflectionMethod->getParameters()[0];
$attributes = $reflectionParameter->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->description; // パラメータの説明だよ
}
```



### クラスプロパティに Attribute

:::note info
DescriptionAttribute の定義は省略します
:::

該当プロパティに対して、定義した DescriptionAttribute を設定

```php
use App\Attribute\DescriptionAttribute;

class TestClass
{
    #[DescriptionAttribute(description: "プロパティの説明だよ")]
    public int $value = 1;
}
```

ReflectionClass クラスの getProperty() メソッドを利用して該当プロパティの Attribute を取得

```php
$reflectionClass = new ReflectionClass(TestClass::class);
$reflectionProperty = $reflectionClass->getProperty('value');
$attributes = $reflectionProperty->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->description; // プロパティの説明だよ
}
```


### クラス定数に Attribute

:::note info
DescriptionAttribute の定義は省略します
:::

クラス定数に定義した DescriptionAttribute を設定

```php
use App\Attribute\DescriptionAttribute;

class TestClass
{
    #[DescriptionAttribute(description: "定数の説明だよ")]
    public const TEST_CONST = 12;
}
```

ReflectionClass クラスの getReflectionConstant() メソッドを利用して該当クラス定数の Attribute を取得

```php
$reflectionClass = new ReflectionClass(DescriptionAttribute::class);
$reflectionConstant = $reflectionClass->getReflectionConstant('TEST_CONST');
$attributes = $reflectionConstant->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->description; // 定数の説明だよ
}
```

## 関数に対しても設定できる

:::note info
TestAttribute の定義は省略します
:::

function に定義した TestAttribute を設定

```php
use App\Attribute\TestAttribute;

#[TestAttribute(message: "関数の説明だよ")]
function testFunction()
{
    // 略
}
```

ReflectionFunction クラスを利用して該当関数の Attribute を取得

```php
$reflectionFunction = new ReflectionFunction('myFunction');
$attributes = $reflectionFunction->getAttributes();

foreach ($attributes as $attribute) {
    $instance = $attribute->newInstance();
    echo $instance->message; // 関数の説明だよ
}
```

# 感想

Reflection関連クラスを利用することで設定した Attribute にアクセス出来るということですね。確かに PHPDoc よりたくさんの情報を設定出来そうな感じではありますが、これは実際のプロジェクトでどう活かせばいいんだろう…全く思い付きません

ライブラリの開発では静的解析が強力になるので重宝しそうな気はしていますが「自分が作ったライブラリにどう活かす？」と自問するとまたも全く思い付きません

どなたかよい使い方を教えて下さい