PHP入門:Attributes(属性)について -vol.1-

スポンサーリンク
PHP入門:Attributes(属性)について -vol.1- 用語解説
PHP入門:Attributes(属性)について -vol.1-
この記事は約7分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

今日は、PHPのAttributes(属性)についてご紹介します。

スポンサーリンク

背景

PHP8.2を利用したAPIを開発しているときにAttributes(属性)を利用したので、そのときの調査内容を備忘としてのこしました。

こちらのサイトを参考にしています。

概要

属性(Attributes)は、コード内の宣言に構造化された、機械可読なメタデータ情報を追加する能力を提供します。クラス、メソッド、関数、パラメータ、プロパティ、クラス定数は、属性の対象となります。属性によって定義されたメタデータは、実行時にReflection APIを使用して検査できます。したがって、属性はコードに直接埋め込まれた設定言語と考えることができます。

属性を使用することで、機能の一般的な実装とアプリケーション内での具体的な使用を切り離すことができます。これは、インターフェースとその実装と似ていますが、インターフェースと実装はコードに関するものであり、属性は追加情報と設定に注釈を付けることに関連しています。インターフェースはクラスに実装できますが、属性はメソッド、関数、パラメータ、プロパティ、クラス定数にも宣言できます。そのため、属性はインターフェースよりも柔軟です。

属性の使用の単純な例は、オプションのメソッドを持つインターフェースに属性を使用するように変換することです。アプリケーション内の操作を表すActionHandlerインターフェースを想像してみましょう。アクションハンドラのいくつかの実装にはセットアップが必要で、他の実装には必要ない場合があります。ActionHandlerを実装するすべてのクラスにsetUp()メソッドの実装を要求する代わりに、属性を使用できます。このアプローチの利点の一つは、属性を複数回使用できることです。

サンプルコード

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

このコードは、PHP 8の属性(Attributes)を使用して、インターフェース、属性、クラスを組み合わせた例です。以下はコードの解説です。

  1. interface ActionHandler: ActionHandlerという名前のインターフェースを定義しています。このインターフェースには execute メソッドが含まれています。
  2. #[Attribute] class SetUp {}: SetUp という属性クラスを定義しています。この属性は #[SetUp] のようにメソッドに注釈として使用できるようになります。
  3. class CopyFile implements ActionHandler: ActionHandler インターフェースを実装した CopyFile クラスを定義しています。このクラスはファイルのコピーを実行するアクションを表します。クラス内には fileNametargetDirectory の2つのプロパティがあります。
  4. #[SetUp] public function fileExists(): fileExists メソッドに #[SetUp] 属性が付いています。このメソッドはファイルの存在を確認し、存在しない場合に RuntimeException をスローします。
  5. #[SetUp] public function targetDirectoryExists(): 同様に、targetDirectoryExists メソッドにも #[SetUp] 属性が付いています。このメソッドはターゲットディレクトリの存在を確認し、存在しない場合には新たにディレクトリを作成し、既存の場合にはディレクトリであることを確認します。
  6. public function execute(): execute メソッドは ActionHandler インターフェースで必要なメソッドで、ファイルのコピーを実行します。
  7. function executeAction(ActionHandler $actionHandler): アクションを実行するための関数を定義しています。この関数は、与えられたアクションハンドラ($actionHandler)に対して、SetUp 属性が付いているメソッドを実行し、それから execute メソッドを実行します。これにより、事前のセットアップが行われ、アクションを実行できます。
  8. $copyAction = new CopyFile(): CopyFile クラスのインスタンスを作成し、$copyAction に代入しています。
  9. $copyAction->fileName および $copyAction->targetDirectory にファイル名とターゲットディレクトリを設定しています。
  10. executeAction($copyAction): executeAction 関数を呼び出して、アクションを実行します。この際、SetUp 属性が付いているメソッド(fileExists および targetDirectoryExists)が事前に実行され、その後にファイルのコピーが行われます。

このコードは、属性を使用してアクションの事前セットアップを実現し、アクションの実行を行う方法を示しています。属性を利用することで、アクションハンドラの実装をより柔軟に構築できます。

おわりに

今日は、PHPのAttributes(属性)についてご紹介しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました