Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】Attribute::flagsプロパティの使い方

flagsプロパティの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

flagsプロパティは、PHP 8で導入されたAttribute(属性)クラスに属し、その属性が適用できるプログラム要素の種類を示す情報を保持するプロパティです。

このプロパティには、定義された属性が、PHPのどのようなコード要素に付与(適用)できるかという情報が格納されます。具体的には、Attribute::TARGET_CLASS(クラス)、Attribute::TARGET_METHOD(メソッド)、Attribute::TARGET_PROPERTY(プロパティ)、Attribute::TARGET_FUNCTION(関数)、Attribute::TARGET_CONSTANT(定数)、Attribute::TARGET_PARAMETER(パラメータ)、Attribute::TARGET_ALL(すべて)といったPHPが提供する定数が、組み合わされた形式で設定されます。

例えば、ある属性がクラスとメソッドの両方に適用可能である場合、このflagsプロパティにはAttribute::TARGET_CLASSAttribute::TARGET_METHODが組み合わされた値が保持されます。これにより、一つの属性定義で複数の適用対象を同時に指定することが可能になります。

開発者がカスタム属性を定義する際、このflagsプロパティに適切なターゲット情報を設定することで、その属性が意図しない場所で使用されるのを防ぎ、コードの整合性と安全性を高めることができます。flagsプロパティは、属性の適用範囲を厳密に制御し、コードの意図を明確にする上で非常に重要な役割を担っています。

構文(syntax)

1#[Attribute(flags: Attribute::TARGET_CLASS)]
2class MyCustomAttribute
3{
4    //
5}

引数(parameters)

引数なし

引数はありません

戻り値(return)

int

Attributeクラスのflagsプロパティは、属性に設定されたフラグを表す整数値を返します。

サンプルコード

PHP 8 Attribute flags を解析する

1<?php
2
3/**
4 * PHP 8 の Attribute 機能を使って、ビットフラグの概念を示すサンプルコードです。
5 *
6 * Attribute::flags プロパティは、アトリビュートが適用可能なターゲット(クラス、メソッドなど)を
7 * 複数のビットフラグの組み合わせとして格納します。
8 * このコードでは、カスタムアトリビュートを定義し、その flags プロパティの値を取得・解析する方法を示します。
9 */
10
11// 1. カスタムアトリビュートを定義します。
12// #[Attribute()] の引数で、このアトリビュートがどこに適用できるかをビットフラグで指定します。
13// ここでは、クラスとメソッドに適用可能であることを指定しています。
14#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
15class MyCustomAttribute
16{
17    // アトリビュートが持つデータ(例として文字列)
18    public function __construct(public string $value)
19    {
20    }
21}
22
23// 2. 定義したアトリビュートを持つクラスを準備します。
24// クラス自体と、その中のメソッドに MyCustomAttribute を適用しています。
25#[MyCustomAttribute("This is a class level attribute.")]
26class ExampleClass
27{
28    #[MyCustomAttribute("This is a method level attribute.")]
29    public function exampleMethod(): void
30    {
31        // メソッドの内容
32    }
33}
34
35// 3. リフレクションAPIを使ってアトリビュートの情報を取得し、flags プロパティを確認します。
36echo "--- Checking MyCustomAttribute's flags ---\n";
37
38// MyCustomAttribute クラスの情報を取得します。
39$reflectionAttributeClass = new ReflectionClass(MyCustomAttribute::class);
40
41// MyCustomAttribute 自体に適用されている #[Attribute(...)] の情報を取得します。
42// ここでは、定義時に指定した Attribute::TARGET_CLASS | Attribute::TARGET_METHOD の情報を持つアトリビュートを取得します。
43$phpInternalAttribute = $reflectionAttributeClass->getAttributes(Attribute::class)[0] ?? null;
44
45if ($phpInternalAttribute) {
46    // Attribute::flags プロパティの値(整数)を取得します。
47    // この値は Attribute::TARGET_* 定数のビット論理和によって構成されています。
48    $flags = $phpInternalAttribute->getFlags();
49
50    echo "Attribute class: " . $reflectionAttributeClass->getName() . "\n";
51    echo "  Its internal Attribute::flags value: " . $flags . " (decimal)\n";
52    echo "  Binary representation: " . decbin($flags) . "\n\n";
53
54    echo "--- Interpreting the flags using bitwise operations ---\n";
55
56    // ビット論理積 (&) を使って、特定のターゲットが含まれているかチェックします。
57    // 例えば、($flags & Attribute::TARGET_CLASS) が Attribute::TARGET_CLASS と同じ値であれば、
58    // TARGET_CLASS が含まれていることになります。
59    if (($flags & Attribute::TARGET_CLASS) === Attribute::TARGET_CLASS) {
60        echo "  - This attribute can be applied to a CLASS.\n";
61    }
62    if (($flags & Attribute::TARGET_METHOD) === Attribute::TARGET_METHOD) {
63        echo "  - This attribute can be applied to a METHOD.\n";
64    }
65    if (($flags & Attribute::TARGET_PROPERTY) === Attribute::TARGET_PROPERTY) {
66        echo "  - This attribute can be applied to a PROPERTY.\n";
67    } else {
68        echo "  - This attribute CANNOT be applied to a PROPERTY.\n";
69    }
70    if (($flags & Attribute::TARGET_FUNCTION) === Attribute::TARGET_FUNCTION) {
71        echo "  - This attribute can be applied to a FUNCTION.\n";
72    } else {
73        echo "  - This attribute CANNOT be applied to a FUNCTION.\n";
74    }
75    echo "\n";
76} else {
77    echo "Could not find the internal Attribute information for MyCustomAttribute.\n";
78}
79
80?>

PHP 8のAttribute::flagsプロパティは、カスタムアトリビュートがコードのどの要素(クラス、メソッド、プロパティなど)に適用できるかを示す、ビットフラグの組み合わせを整数値で返します。このプロパティは引数を持ちません。

サンプルコードでは、まずMyCustomAttributeというカスタムアトリビュートを定義しています。このアトリビュートの定義時に、#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]のようにビットフラグを組み合わせて指定することで、そのアトリビュートが適用可能なターゲットを宣言しています。

次に、リフレクションAPIを利用してMyCustomAttributeの定義情報を取得し、その内部的なAttributeが持つflagsプロパティの値をgetFlags()メソッドで取得します。この戻り値は整数型で、アトリビュートの定義時に設定されたAttribute::TARGET_*定数のビット論理和を表しています。

コードの後半では、取得したflagsの値と各Attribute::TARGET_*定数とのビット論理積(&演算子)を用いて、MyCustomAttributeが具体的にどのターゲット(クラス、メソッド、プロパティ、関数など)に適用できるかを一つずつ判定しています。これにより、アトリビュートがどのように定義され、その適用範囲がプログラムによってどのように解釈されるかを確認できます。

「ビットフラグ」とは、複数のON/OFF情報を1つの整数値にまとめて表現する効率的な方法です。Attribute::flagsプロパティは、PHPのアトリビュートが適用可能な要素(クラス、メソッドなど)をこのビットフラグで管理しています。サンプルコードでは、#[Attribute(...)]でカスタムアトリビュートの適用ターゲットを|(ビット論理和)で設定し、getFlags()メソッドでその整数値を取得しています。この値は、&(ビット論理積)を使って個々のターゲットフラグが含まれているか正確に判定できます。設定を誤ると、アトリビュートを意図しない場所に適用できてしまったり、逆に適用できなかったりするため、適切なフラグ設定とビット演算による確認が不可欠です。リフレクションAPIは、実行時にアトリビュートの情報を動的に取得・解析する重要な手段となります。

PHP Attribute::flags をビット演算で確認する

1<?php
2
3/**
4 * カスタムアトリビュートを定義します。
5 *
6 * #[Attribute(...)] 構文を使って、このアトリビュートが適用できるターゲット(適用範囲)と
7 * その振る舞いを指定します。これらの指定は内部的に Attribute::flags プロパティにマッピングされます。
8 *
9 * Attribute::TARGET_ALL は、このアトリビュートがクラス、プロパティ、メソッドなど、
10 * 全てのPHP要素に適用可能であることを示します。
11 *
12 * Attribute::IS_REPEATABLE は、同じPHP要素に対してこのアトリビュートを複数回適用できることを示します。
13 *
14 * これらのフラグはビットマスクであり、ビット論理和演算子 `|` を使って組み合わせて指定します。
15 */
16#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
17class MyConfiguration
18{
19    /**
20     * アトリビュートのコンストラクタ。
21     * @param string $key 設定キー
22     * @param mixed $value 設定値
23     */
24    public function __construct(
25        public string $key,
26        public mixed $value
27    ) {}
28}
29
30/**
31 * 上で定義した MyConfiguration アトリビュートを使用するクラスの例です。
32 */
33#[MyConfiguration("appName", "ExampleApp")]
34#[MyConfiguration("version", "1.0.0")] // Attribute::IS_REPEATABLE のため複数回適用可能
35class Application
36{
37    /**
38     * プロパティにアトリビュートを適用します。
39     */
40    #[MyConfiguration("dbHost", "localhost")]
41    public string $databaseHost = 'localhost';
42
43    /**
44     * メソッドにアトリビュートを適用します。
45     */
46    #[MyConfiguration("maxConnections", 100)]
47    public function initialize(): void
48    {
49        echo "Application initialized.\n";
50    }
51}
52
53/**
54 * Reflection API を使ってアトリビュートの情報を取得し、そのフラグ値(Attribute::flags)を確認します。
55 * Attribute::flags は ReflectionAttribute::getFlags() メソッドを通じて取得できます。
56 */
57echo "--- MyConfiguration アトリビュートの定義フラグを確認 ---\n";
58
59// MyConfiguration クラスの ReflectionClass インスタンスを作成
60$reflectionMyConfig = new ReflectionClass(MyConfiguration::class);
61
62// MyConfiguration クラス自体に付けられた #[Attribute(...)] を取得します。
63// これは、MyConfiguration アトリビュートの定義情報(ターゲットや反復可能性)を含みます。
64$reflectionAttributeDefinition = $reflectionMyConfig->getAttributes(Attribute::class)[0];
65
66// ReflectionAttribute::getFlags() メソッドで Attribute::flags プロパティに相当する値を取得します。
67$flags = $reflectionAttributeDefinition->getFlags();
68echo "MyConfiguration アトリビュートの定義フラグ値 (Attribute::flags に相当): " . $flags . " (10進数)\n";
69
70// ビット論理積演算子 `&` を使って、特定のフラグが含まれているかを確認します。
71echo "  - TARGET_ALL が含まれていますか: " . (($flags & Attribute::TARGET_ALL) === Attribute::TARGET_ALL ? "はい" : "いいえ") . "\n";
72echo "  - IS_REPEATABLE が含まれていますか: " . (($flags & Attribute::IS_REPEATABLE) === Attribute::IS_REPEATABLE ? "はい" : "いいえ") . "\n";
73echo "  - TARGET_PROPERTY が含まれていますか: " . (($flags & Attribute::TARGET_PROPERTY) === Attribute::TARGET_PROPERTY ? "はい" : "いいえ") . "\n";
74
75
76echo "\n--- Application クラスに適用された MyConfiguration アトリビュートのフラグを確認 ---\n";
77
78$reflectionApplication = new ReflectionClass(Application::class);
79
80// クラスに適用された MyConfiguration アトリビュートを取得
81echo "Application クラスに直接適用されたアトリビュート:\n";
82foreach ($reflectionApplication->getAttributes(MyConfiguration::class) as $attr) {
83    $instance = $attr->newInstance();
84    echo "  - MyConfiguration(\"{$instance->key}\", \"{$instance->value}\")\n";
85    // 適用されたアトリビュートの ReflectionAttribute インスタンスからも、定義時のフラグ値を取得できます。
86    echo "    取得されたフラグ値: " . $attr->getFlags() . "\n";
87}
88
89// プロパティに適用された MyConfiguration アトリビュートを取得
90echo "\nApplication::\$databaseHost プロパティに適用されたアトリビュート:\n";
91$reflectionProperty = $reflectionApplication->getProperty('databaseHost');
92foreach ($reflectionProperty->getAttributes(MyConfiguration::class) as $attr) {
93    $instance = $attr->newInstance();
94    echo "  - MyConfiguration(\"{$instance->key}\", \"{$instance->value}\")\n";
95    echo "    取得されたフラグ値: " . $attr->getFlags() . "\n";
96}
97
98// メソッドに適用された MyConfiguration アトリビュートを取得
99echo "\nApplication::initialize() メソッドに適用されたアトリビュート:\n";
100$reflectionMethod = $reflectionApplication->getMethod('initialize');
101foreach ($reflectionMethod->getAttributes(MyConfiguration::class) as $attr) {
102    $instance = $attr->newInstance();
103    echo "  - MyConfiguration(\"{$instance->key}\", \"{$instance->value}\")\n";
104    echo "    取得されたフラグ値: " . $attr->getFlags() . "\n";
105}
106
107?>

PHP 8で導入されたアトリビュート(属性)の動作を制御するAttribute::flagsプロパティは、アトリビュートがどのような要素に適用できるか、そして同じ要素に複数回適用できるかといった定義情報を示すint型の値です。このflagsは、アトリビュートを定義する際に#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]のように、Attribute::TARGET_*定数やAttribute::IS_REPEATABLE定数をビット論理和演算子 | で組み合わせて指定することで設定されます。

サンプルコードでは、MyConfigurationというカスタムアトリビュートを定義し、Attribute::TARGET_ALL(全てのPHP要素に適用可能)とAttribute::IS_REPEATABLE(複数回適用可能)のフラグを設定しています。これにより、MyConfigurationアトリビュートはクラス、プロパティ、メソッドのどこにでも適用でき、同じ要素に複数回記述することも可能です。

プログラム実行中にアトリビュートの定義情報を取得するには、Reflection APIを使用します。具体的には、ReflectionAttribute::getFlags()メソッドを呼び出すことで、定義時に設定されたAttribute::flagsに相当するint型の値を取得できます。取得したフラグ値とAttribute定数をビット論理積演算子 & で比較することで、特定の設定(例えばTARGET_ALLIS_REPEATABLE)が有効になっているかを効率的に確認できるため、アトリビュートのルールを動的に検査する際に役立ちます。

PHPのアトリビュートを定義する際、Attribute::flags はそのアトリビュートがどこに適用できるか、複数回使えるかといった情報をビット列として内部的に保持します。サンプルコードでは、Attribute::TARGET_ALLAttribute::IS_REPEATABLE のような複数のルールを | (ビット論理和) で組み合わせて指定しています。これらのフラグの値は、ReflectionAttribute::getFlags() メソッドを通じて取得できます。取得したフラグに特定の定義が含まれているかを確認する際は、& (ビット論理積) を使用します。このビット演算の理解は、アトリビュートを正確に定義し、プログラムでその情報を活用するために不可欠です。flagsプロパティは直接アクセスせず、Reflection APIを通じて値を取得する点にご注意ください。

PHP AttributeでEnumフラグを扱う

1<?php
2
3/**
4 * Enum を Attribute フラグとして使用する例
5 */
6
7enum Permission: int
8{
9    case Read = 1;
10    case Write = 2;
11    case Execute = 4;
12}
13
14#[Attribute(flags: true)]
15class AccessControl
16{
17    public function __construct(public Permission $permission) {}
18}
19
20#[AccessControl(Permission::Read)]
21class Document
22{
23    // ...
24}
25
26$reflection = new ReflectionClass(Document::class);
27$attributes = $reflection->getAttributes(AccessControl::class);
28
29foreach ($attributes as $attribute) {
30    $instance = $attribute->newInstance();
31    echo "Permission: " . $instance->permission->name . PHP_EOL; // Permission: Read
32    echo "Value: " . $instance->permission->value . PHP_EOL; // Value: 1
33}

このサンプルコードは、PHP 8 で導入された Attribute 機能と Enum を組み合わせて、フラグとして属性を定義する方法を示しています。

まず、Permission という Enum を定義しています。この Enum は int 型をベースとし、Read, Write, Execute という3つのケースを持ち、それぞれ 1, 2, 4 という整数値を割り当てています。これらの値は、ビット演算で組み合わせることを想定したフラグとして利用できます。

次に、AccessControl という Attribute クラスを定義しています。#[Attribute(flags: true)] という記述により、このクラスが Attribute として使用されることを宣言しています。flags: true は、この Attribute が Enum のフラグを受け取ることを示します。コンストラクタでは、Permission Enum を引数として受け取り、プロパティ $permission に格納します。

Document クラスは、#[AccessControl(Permission::Read)] という Attribute を持っています。これにより、Document クラスに AccessControl Attribute が付与され、その引数として Permission::Read が渡されます。

コードの後半部分では、Reflection API を使用して Document クラスの Attribute 情報を取得しています。ReflectionClassDocument クラスをリフレクションし、getAttributes(AccessControl::class)AccessControl Attribute を取得します。

最後に、取得した Attribute インスタンスから $permission プロパティの値を取り出し、その名前 (name) と値 (value) を出力しています。この例では、Permission: ReadValue: 1 が出力されます。

このように、Attribute と Enum を組み合わせることで、クラスやメソッドに付与するメタデータをより柔軟かつ型安全に定義することができます。flags: true を使用することで、Enum のフラグを Attribute の引数として扱うことが可能になり、より表現力豊かなコードを実現できます。

#[Attribute(flags: true)]は、Attributeクラスを定義する際に、enumをフラグとして扱えるようにするためのものです。flags: trueを指定することで、Attributeの引数に複数のenum値をビット演算で組み合わせた値を渡せるようになります。このサンプルコードでは、Permission enumの値をそのままAttributeに渡していますが、複数のPermissionを組み合わせる場合は、Permission::Read | Permission::Writeのようにビット演算子を使用します。また、enumの各ケースには一意な整数値を割り当てる必要があります。値が重複すると、意図しない動作になる可能性があるため注意が必要です。Reflection APIを利用してAttributeの情報を取得する際、newInstance()でAttributeクラスのインスタンスを生成してから、プロパティにアクセスする必要があります。

関連コンテンツ