Open2
[Symfony] アノテーションと属性の書き方について

symfony ではphpのアノテーションや属性をよく使う。資料ではアノテーションで書かれているけれど、属性の方の書き方をしたい事がある。
そう言う場合に、このサンプルのアノテーションを属性として書く場合、どういう感じに書くのが良いのかという事を調べてる。
ChatGPT に php の アノテーションと属性の違いについて聞いた、それが次。
PHPにおける「アノテーション」と「属性(Attribute)」は、メタデータをコードに付加するための2つの異なるアプローチです。両者は似ている機能を提供しますが、実装方法と使用される文脈が異なります。
アノテーション
-
定義: アノテーションは、PHPのコメント内に特定のフォーマットで記述されるメタデータです。通常は
@
記号に続いてキーワードが来る形式をとります。アノテーションは、PHP自体によって解釈されるのではなく、フレームワークやライブラリが独自に解析し利用します。 - 使用例: SymfonyやDoctrineなどのフレームワークやライブラリで広く使用されています。これらのツールはアノテーションを解析し、ルーティングの定義、ORMマッピング、セキュリティチェックなどに使用します。
- 特徴: コメント内に記述されるため、PHPの実行時には無視されます。アノテーションを解析するためには、フレームワークやライブラリが提供する特定のパーサーが必要です。
属性(Attribute)
-
定義: 属性は、PHP 8.0で導入された新しい機能です。コードの宣言(クラス、プロパティ、メソッド、関数など)にメタデータを付与するための構文です。属性は
#[AttributeName]
の形式をとり、PHPによってネイティブにサポートされています。 - 使用例: PHP 8.0以降のバージョンで使用でき、フレームワークやライブラリだけでなく、PHP自体によっても認識されます。属性は、アノテーションと同様に、ルーティング定義、ORMマッピングなどに使用されますが、PHPのランタイムによって直接サポートされるため、使用と解析がより効率的です。
- 特徴: PHPのコードとして解釈されるため、コメントではなく実際のコードの一部として扱われます。これにより、タイプセーフであり、リフレクションAPIを通じてプログラムから直接アクセスできます。
違いの要点
- 文法と解釈: アノテーションはコメントとして記述され、専用のパーサーによって解析される必要があります。一方、属性はPHPの構文として認識され、PHPランタイムによって直接解釈されます。
- タイプセーフ: 属性はPHPの型システムの一部として機能するため、よりタイプセーフです。アノテーションは文字列ベースであり、間違いが起きやすい場合があります。
- パフォーマンス: 属性はPHPによってネイティブにサポートされているため、アノテーションを解析する必要がなく、パフォーマンスが向上する可能性があります。
- バージョン: 属性はPHP 8.0以降でのみ使用可能です。アノテーションは以前のバージョンのPHPでも使用されてきました。

Entity にEntity Listener を指定する際、次のようにするとあった。
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\EntityListeners({"App\EventEntityListener\LifeListener"})
*/
class LifeActivityLog
{
// エンティティのプロパティとメソッド
}
上記の @ORM\EntityListeners({"App\EventEntityListener\LifeListener"})
の所のアノテーションの記述を、属性として書きたいときは次。
#[ORM\EntityListeners(["App\EventEntityListener\LifeListener"])]
chatGPTに尋ねた所、次の様に返された。
PHPの属性を使用する場合、クラス名は::class構文を用いて指定するのが一般的です。
確かに <class_name>::class
としたほうが良い感じな書き方な気がする。という事で次の書き方がいいなあと思った。
use Doctrine\ORM\Mapping as ORM;
use App\Repository\LifeActivityLogRepository;
use App\EventEntityListener\LifeListener;
#[ORM\Entity(repositoryClass: LifeActivityLogRepository::class)]
#[ORM\EntityListeners([LifeListener::class])]
class LifeActivityLog
{
}