PHP 上的枚举

2022-08-30 05:45:31

我知道PHP还没有原生枚举。但是我已经从Java世界中习惯了它们。我很想使用枚举作为一种方式来提供IDE的自动完成功能可以理解的预定义值。

常量可以解决问题,但存在命名空间冲突问题,并且(或者实际上是因为)它们是全局的。数组没有命名空间问题,但它们太模糊了,它们可以在运行时被覆盖,并且IDE很少知道如何在没有额外的静态分析注释或属性的情况下自动填充其键。

是否有任何您常用的解决方案/解决方法?有没有人记得PHP人员是否对枚举有任何想法或决定?


答案 1

根据用例,我通常会使用如下所示的简单内容:

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

作为旁注,每当我在数据不会更改的静态/const类(例如在枚举中)上使用反射至少一次时,我都会缓存这些反射调用的结果,因为每次使用新的反射对象最终都会对性能产生明显的影响(存储在多个枚举的关联数组中)。

现在大多数人终于升级到至少5.3,并且可用,这当然也是一个可行的选择 - 只要你不介意在整个代码库中具有实际枚举实例化的传统不直观的概念。在上面的示例中,并且根本无法实例化,也不应该是实例化的。SplEnumBasicEnumDaysOfWeek


答案 2

还有一个本机扩展。斯普勒纳姆酒店

SplEnum提供了在PHP中本机模拟和创建枚举对象的能力。

http://www.php.net/manual/en/class.splenum.php

注意力:

https://www.php.net/manual/en/spl-types.installation.php

PECL 扩展未与 PHP 捆绑在一起。

此 PECL 扩展的 DLL 当前不可用。


推荐