PHPの列挙について質問する

PHPの列挙について質問する

PHP にはまだネイティブの列挙型がないことは知っています。しかし、私は Java の世界からそれらに慣れてきました。IDE の自動補完機能が理解できる定義済みの値を与える方法として列挙型を使いたいと思っています。

定数はうまく機能しますが、名前空間の衝突の問題があり、(または実際には)グローバルであるためです。配列には名前空間の問題はありませんが、あまりにも曖昧で、実行時に上書きされる可能性があり、追加の静的分析アノテーションや属性なしでキーを自動入力する方法を IDE が認識することはほとんどありません。

よく使用する解決策や回避策はありますか? PHP 開発者が列挙に関して何か考えや決定をしたかどうか覚えている人はいますか?

ベストアンサー1

PHP 8.1 以降では、列挙型がサポートされています。

https://www.php.net/manual/en/language.types.enumerations.php

enum DaysOfWeek: int
{
    case Sunday = 0;
    case Monday = 1;
    // etc.
}
$today = DaysOfWeek::Sunday;
var_dump($today->value); // 0
var_dump($today->name); // "Sunday"

PHP 8.0 以前

ユースケースに応じて、通常は次のような単純なものを使用します。

abstract class DaysOfWeek
{
    const Sunday = 0;
    const Monday = 1;
    // etc.
}

$today = DaysOfWeek::Sunday;

しかし、他のユースケースでは、定数や値の検証をさらに必要とする場合があります。以下のリフレクションに関するコメントに基づいて、その他の注意事項以下に、より幅広いケースに対応できる拡張例を示します。

abstract class BasicEnum {
    private static $constCacheArray = NULL;

    private static function getConstants() {
        if (self::$constCacheArray == NULL) {
            self::$constCacheArray = [];
        }
        $calledClass = get_called_class();
        if (!array_key_exists($calledClass, self::$constCacheArray)) {
            $reflect = new ReflectionClass($calledClass);
            self::$constCacheArray[$calledClass] = $reflect->getConstants();
        }
        return self::$constCacheArray[$calledClass];
    }

    public static function isValidName($name, $strict = false) {
        $constants = self::getConstants();

        if ($strict) {
            return array_key_exists($name, $constants);
        }

        $keys = array_map('strtolower', array_keys($constants));
        return in_array(strtolower($name), $keys);
    }

    public static function isValidValue($value, $strict = true) {
        $values = array_values(self::getConstants());
        return in_array($value, $values, $strict);
    }
}

BasicEnum を拡張する単純な列挙クラスを作成することで、単純な入力検証に次のようなメソッドを使用できるようになります。

abstract class DaysOfWeek extends BasicEnum {
    const Sunday = 0;
    const Monday = 1;
    const Tuesday = 2;
    const Wednesday = 3;
    const Thursday = 4;
    const Friday = 5;
    const Saturday = 6;
}

DaysOfWeek::isValidName('Humpday');                  // false
DaysOfWeek::isValidName('Monday');                   // true
DaysOfWeek::isValidName('monday');                   // true
DaysOfWeek::isValidName('monday', $strict = true);   // false
DaysOfWeek::isValidName(0);                          // false

DaysOfWeek::isValidValue(0);                         // true
DaysOfWeek::isValidValue(5);                         // true
DaysOfWeek::isValidValue(7);                         // false
DaysOfWeek::isValidValue('Friday');                  // false

ちなみに、データが変更されない静的/定数クラス(列挙型など) でリフレクションを少なくとも 1 回使用するたびに、そのリフレクション呼び出しの結果をキャッシュします。これは、毎回新しいリフレクション オブジェクトを使用すると、最終的にパフォーマンスに顕著な影響が出るためです (複数の列挙型の場合は連想配列に格納されます)。

現在、ほとんどの人が5.3 以上にアップグレードし、が利用可能になっているので、コードベース全体で実際の列挙型のインスタンス化SplEnumを行うという従来は直感に反する概念を気にしない限り、これも確かに実行可能なオプションです。上記の例では、と はまったくインスタンス化できず、また、インスタンス化すべきでもありません。BasicEnumDaysOfWeek

おすすめ記事