我知道,PHP没有机枚举。但我已经习惯了他们从Java的世界。我会喜欢使用枚举作为一种方式给予预定的价值观IDEs'自动完成的功能可理解的。

常做的伎俩,但是还有空间碰撞的问题和(或实际上 )他们是全球性的。阵列没有空间问题,但是他们太模糊,他们可以复盖在运行时和IDEs很少(从来没有?) 知道如何填写他们的钥匙。

是否有任何解决方案/解决方法通常使用?任何人都不会记得是否PHP们有任何想法,或者决定围绕枚举?

有帮助吗?

解决方案

根据用例,我通常会使用 simple 之类的内容,如下所示:

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,并且 SplEnum 可用,这当然是一个可行的选择 - 只要你没有'请注意在整个代码库中使用实际枚举实例化的传统不直观的概念。在上面的例子中, BasicEnum DaysOfWeek 根本不能实例化,也不应该实例化。

其他提示

也有原生扩展。 SplEnum

  

SplEnum提供了模拟和创建枚举对象的功能   原生于PHP。

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

类常数怎么样?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

    public function echoConstant()
    {
        echo self::SOME_CONSTANT;
    }
}

echo YourClass::SOME_CONSTANT;

$c = new YourClass;
$c->echoConstant();

上面的答案很棒。但是,如果您以两种不同的方式 extend ,那么无论哪个扩展首先导致对函数的调用都将创建缓存。然后,所有后续呼叫都将使用此缓存,无论呼叫是由...发起的哪个分机。

要解决此问题,请将变量和第一个函数替换为:

private static $constCacheArray = null;

private static function getConstants() {
    if (self::$constCacheArray === null) self::$constCacheArray = array();

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

    return self::$constCacheArray[$calledClass];
}

我使用 interface 代替 class

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

var $today = DaysOfWeek::Sunday;

我使用了常量类:

class Enum {
    const NAME       = 'aaaa';
    const SOME_VALUE = 'bbbb';
}

print Enum::NAME;

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

final class TestEnum
{

    private static 

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>values = [ 'FOO' => 1, 'BAR' => 2, 'QUX' => 3, ]; private static

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>instances = []; public static function __getStatic($name) { if (isset(static::

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>values[$name])) { if (empty(static::

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>instances[$name])) { static::

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>instances[$name] = new static($name); } return static::

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>instances[$name]; } throw new Exception(sprintf('Invalid enumeration value, "%s"', $name)); } private

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>value; public function __construct($name) { $this->_value = static::

我在这里评论了其他一些答案,所以我想我也会权衡。 在一天结束时,由于PHP不支持类型枚举,您可以采用以下两种方式之一:破解类型枚举,或者使用它们非常难以有效地破解这一事实。

我更喜欢接受这个事实,而是使用 const 方法,其他答案在这里以某种方式使用:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        throw new NotSupportedException(); // 
    }

    final private function __clone()
    {
        throw new NotSupportedException();
    }

    final public static function toArray()
    {
        return (new ReflectionClass(static::class))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

枚举示例:

final class ResponseStatusCode extends Enum
{

    const OK                         = 200;
    const CREATED                    = 201;
    const ACCEPTED                   = 202;
    // ...
    const SERVICE_UNAVAILABLE        = 503;
    const GATEWAY_TIME_OUT           = 504;
    const HTTP_VERSION_NOT_SUPPORTED = 505;

}

使用 Enum 作为基类,所有其他枚举扩展所允许的辅助方法,例如 toArray isValid ,等等。对我来说,键入的枚举(和管理他们的实例)最终太乱了。


假设

如果,则存在 __ getStatic 魔术方法(,最好是 __ equals 魔术方法)这可以通过一种多重模式来缓解。

以下是假设; 不会工作,但也许有一天会

<*>values[$name]; } public function __equals($object) { if ($object instanceof static) { return $object->_value === $this->_value; } return $object === $this->_value; } } $foo = TestEnum::$FOO; // object(TestEnum)#1 (1) { // ["_value":"TestEnum":private]=> // int(1) // } $zap = TestEnum::$ZAP; // Uncaught exception 'Exception' with message // 'Invalid enumeration member, "ZAP"' $qux = TestEnum::$QUX; TestEnum::$QUX == $qux; // true 'hello world!' == $qux; // false

好吧,对于像php这样简单的java,我使用:

class SomeTypeName {
    private static $enum = array(1 => "Read", 2 => "Write");

    public function toOrdinal($name) {
        return array_search($name, self::$enum);
    }

    public function toString($ordinal) {
        return self::$enum[$ordinal];
    }
}

并称之为:

SomeTypeName::toOrdinal("Read");
SomeTypeName::toString(1);

但我是一名PHP初学者,在语法方面苦苦挣扎,所以这可能不是最好的方法。我用类常量实验了一些,使用Reflection从它的值中获取常量名称,可能更整洁。

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

abstract class TypedEnum
{
    private static 

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

final class DaysOfWeek extends TypedEnum
{
    public static function Sunday() { return self::_create(0); }    
    public static function Monday() { return self::_create(1); }
    public static function Tuesday() { return self::_create(2); }   
    public static function Wednesday() { return self::_create(3); }
    public static function Thursday() { return self::_create(4); }  
    public static function Friday() { return self::_create(5); }
    public static function Saturday() { return self::_create(6); }      
}

示例枚举:

function saveEvent(DaysOfWeek $weekDay, $comment)
{
    // store week day numeric value and comment:
    $myDatabase->save('myeventtable', 
       array('weekday_id' => $weekDay->getValue()),
       array('comment' => $comment));
}

// call the function, note: DaysOfWeek::Monday() returns an object of type DaysOfWeek
saveEvent(DaysOfWeek::Monday(), 'some comment');

使用示例:

$monday1 = DaysOfWeek::Monday();
$monday2 = DaysOfWeek::Monday();
$monday1 === $monday2; // true

请注意,相同枚举条目的所有实例都是相同的:

function getGermanWeekDayName(DaysOfWeek $weekDay)
{
    switch ($weekDay)
    {
        case DaysOfWeek::Monday(): return 'Montag';
        case DaysOfWeek::Tuesday(): return 'Dienstag';
        // ...
}

您也可以在switch语句中使用它:

$monday = DaysOfWeek::fromValue(2);
$tuesday = DaysOfWeek::fromName('Tuesday');

您还可以按名称或值创建枚举条目:

$wednesday = DaysOfWeek::Wednesday()
echo $wednesDay->getName(); // Wednesday

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues; private

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>value; private

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>name; private function __construct($value, $name) { $this->_value = $value; $this->_name = $name; } private static function _fromGetter($getter, $value) { $reflectionClass = new ReflectionClass(get_called_class()); $methods = $reflectionClass->getMethods(ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PUBLIC); $className = get_called_class(); foreach($methods as $method) { if ($method->class === $className) { $enumItem = $method->invoke(null); if ($enumItem instanceof $className && $enumItem->$getter() === $value) { return $enumItem; } } } throw new OutOfRangeException(); } protected static function _create($value) { if (self::

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues === null) { self::

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues = array(); } $className = get_called_class(); if (!isset(self::

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues[$className])) { self::

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues[$className] = array(); } if (!isset(self::

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues[$className][$value])) { $debugTrace = debug_backtrace(); $lastCaller = array_shift($debugTrace); while ($lastCaller['class'] !== $className && count($debugTrace) > 0) { $lastCaller = array_shift($debugTrace); } self::

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues[$className][$value] = new static($value, $lastCaller['function']); } return self::

四年后,我又遇到了这个。我目前的方法是这样,因为它允许在IDE中完成代码以及类型安全:

基类:

<*>

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>instancedValues[$className][$value]; } public static function fromValue($value) { return self::_fromGetter('getValue', $value); } public static function fromName($value) { return self::_fromGetter('getName', $value); } public function getValue() { return $this->_value; } public function getName() { return $this->_name; } }

示例枚举:

<*>

使用示例:

<*>

请注意,相同枚举条目的所有实例都是相同的:

<*>

您也可以在switch语句中使用它:

<*>

您还可以按名称或值创建枚举条目:

<*>

或者您可以从现有的枚举条目中获取名称(即函数名称):

<*>

如果您需要使用全局唯一的枚举(即使在比较不同枚举之间的元素时)并且易于使用,请随意使用以下代码。我还添加了一些我觉得有用的方法。您可以在代码最顶部的注释中找到示例。

<?php

/**
 * Class Enum
 * 
 * @author Christopher Fox <christopher.fox@gmx.de>
 *
 * @version 1.0
 *
 * This class provides the function of an enumeration.
 * The values of Enum elements are unique (even between different Enums)
 * as you would expect them to be.
 *
 * Constructing a new Enum:
 * ========================
 *
 * In the following example we construct an enum called "UserState"
 * with the elements "inactive", "active", "banned" and "deleted".
 * 
 * <code>
 * Enum::Create('UserState', 'inactive', 'active', 'banned', 'deleted');
 * </code>
 *
 * Using Enums:
 * ============
 *
 * The following example demonstrates how to compare two Enum elements
 *
 * <code>
 * var_dump(UserState::inactive == UserState::banned); // result: false
 * var_dump(UserState::active == UserState::active); // result: true
 * </code>
 *
 * Special Enum methods:
 * =====================
 *
 * Get the number of elements in an Enum:
 *
 * <code>
 * echo UserState::CountEntries(); // result: 4
 * </code>
 *
 * Get a list with all elements of the Enum:
 *
 * <code>
 * $allUserStates = UserState::GetEntries();
 * </code>
 *
 * Get a name of an element:
 *
 * <code>
 * echo UserState::GetName(UserState::deleted); // result: deleted
 * </code>
 *
 * Get an integer ID for an element (e.g. to store as a value in a database table):
 * This is simply the index of the element (beginning with 1).
 * Note that this ID is only unique for this Enum but now between different Enums.
 *
 * <code>
 * echo UserState::GetDatabaseID(UserState::active); // result: 2
 * </code>
 */
class Enum
{

    /**
     * @var Enum $instance The only instance of Enum (Singleton)
     */
    private static $instance;

    /**
     * @var array $enums    An array of all enums with Enum names as keys
     *          and arrays of element names as values
     */
    private $enums;

    /**
     * Constructs (the only) Enum instance
     */
    private function __construct()
    {
        $this->enums = array();
    }

    /**
     * Constructs a new enum
     *
     * @param string $name The class name for the enum
     * @param mixed 

如果您需要使用全局唯一的枚举(即使在比较不同枚举之间的元素时)并且易于使用,请随意使用以下代码。我还添加了一些我觉得有用的方法。您可以在代码最顶部的注释中找到示例。

<*> A list of strings to use as names for enum entries */ public static function Create($name,

如果您需要使用全局唯一的枚举(即使在比较不同枚举之间的元素时)并且易于使用,请随意使用以下代码。我还添加了一些我觉得有用的方法。您可以在代码最顶部的注释中找到示例。

<*>) { // Create (the only) Enum instance if this hasn't happened yet if (self::$instance===null) { self::$instance = new Enum(); } // Fetch the arguments of the function $args = func_get_args(); // Exclude the "name" argument from the array of function arguments, // so only the enum element names remain in the array array_shift($args); self::$instance->add($name, $args); } /** * Creates an enumeration if this hasn't happened yet * * @param string $name The class name for the enum * @param array $fields The names of the enum elements */ private function add($name, $fields) { if (!array_key_exists($name, $this->enums)) { $this->enums[$name] = array(); // Generate the code of the class for this enumeration $classDeclaration = "class " . $name . " {\n" . "private static \$name = '" . $name . "';\n" . $this->getClassConstants($name, $fields) . $this->getFunctionGetEntries($name) . $this->getFunctionCountEntries($name) . $this->getFunctionGetDatabaseID() . $this->getFunctionGetName() . "}"; // Create the class for this enumeration eval($classDeclaration); } } /** * Returns the code of the class constants * for an enumeration. These are the representations * of the elements. * * @param string $name The class name for the enum * @param array $fields The names of the enum elements * * @return string The code of the class constants */ private function getClassConstants($name, $fields) { $constants = ''; foreach ($fields as $field) { // Create a unique ID for the Enum element // This ID is unique because class and variables // names can't contain a semicolon. Therefore we // can use the semicolon as a separator here. $uniqueID = $name . ";" . $field; $constants .= "const " . $field . " = '". $uniqueID . "';\n"; // Store the unique ID array_push($this->enums[$name], $uniqueID); } return $constants; } /** * Returns the code of the function "GetEntries()" * for an enumeration * * @param string $name The class name for the enum * * @return string The code of the function "GetEntries()" */ private function getFunctionGetEntries($name) { $entryList = ''; // Put the unique element IDs in single quotes and // separate them with commas foreach ($this->enums[$name] as $key => $entry) { if ($key > 0) $entryList .= ','; $entryList .= "'" . $entry . "'"; } return "public static function GetEntries() { \n" . " return array(" . $entryList . ");\n" . "}\n"; } /** * Returns the code of the function "CountEntries()" * for an enumeration * * @param string $name The class name for the enum * * @return string The code of the function "CountEntries()" */ private function getFunctionCountEntries($name) { // This function will simply return a constant number (e.g. return 5;) return "public static function CountEntries() { \n" . " return " . count($this->enums[$name]) . ";\n" . "}\n"; } /** * Returns the code of the function "GetDatabaseID()" * for an enumeration * * @return string The code of the function "GetDatabaseID()" */ private function getFunctionGetDatabaseID() { // Check for the index of this element inside of the array // of elements and add +1 return "public static function GetDatabaseID(\$entry) { \n" . "\$key = array_search(\$entry, self::GetEntries());\n" . " return \$key + 1;\n" . "}\n"; } /** * Returns the code of the function "GetName()" * for an enumeration * * @return string The code of the function "GetName()" */ private function getFunctionGetName() { // Remove the class name from the unique ID // and return this value (which is the element name) return "public static function GetName(\$entry) { \n" . "return substr(\$entry, strlen(self::\$name) + 1 , strlen(\$entry));\n" . "}\n"; } } ?>

我也喜欢java中的枚举,因此我以这种方式编写我的枚举,我认为这是Java枚举中最类似的行为,当然,如果有人想从java使用更多方法应该在这里写或者在抽象类中,但核心思想嵌入在下面的代码中


class FruitsEnum {

    static $APPLE = null;
    static $ORANGE = null;

    private $value = null;

    public static $map;

    public function __construct($value) {
        $this->value = $value;
    }

    public static function init () {
        self::$APPLE  = new FruitsEnum("Apple");
        self::$ORANGE = new FruitsEnum("Orange");
        //static map to get object by name - example Enum::get("INIT") - returns Enum::$INIT object;
        self::$map = array (
            "Apple" => self::$APPLE,
            "Orange" => self::$ORANGE
        );
    }

    public static function get($element) {
        if($element == null)
            return null;
        return self::$map[$element];
    }

    public function getValue() {
        return $this->value;
    }

    public function equals(FruitsEnum $element) {
        return $element->getValue() == $this->getValue();
    }

    public function __toString () {
        return $this->value;
    }
}
FruitsEnum::init();

var_dump(FruitsEnum::$APPLE->equals(FruitsEnum::$APPLE)); //true
var_dump(FruitsEnum::$APPLE->equals(FruitsEnum::$ORANGE)); //false
var_dump(FruitsEnum::$APPLE instanceof FruitsEnum); //true
var_dump(FruitsEnum::get("Apple")->equals(FruitsEnum::$APPLE)); //true - enum from string
var_dump(FruitsEnum::get("Apple")->equals(FruitsEnum::get("Orange"))); //false

我找到了 这个图书馆 在审查和我认为它提供了一个很体面的替代的答案在这里。

PHP枚举行的灵感来自SplEnum

  • 你可以类-提示: function setAction(Action $action) {
  • 你可以丰富的枚举的方法(例如 format, parse, …)
  • 你可以延长枚举添加新的价值(让你的enum final 防止它)
  • 你可以得到一个列表中的所有可能的价值(见下文)

宣言

<?php
use MyCLabs\Enum\Enum;

/**
 * Action enum
 */
class Action extends Enum
{
    const VIEW = 'view';
    const EDIT = 'edit';
}

使用

<?php
$action = new Action(Action::VIEW);

// or
$action = Action::VIEW();

类型提枚举,值:

<?php
function setAction(Action $action) {
    // ...
}

我在PHP中看到的最常见的解决方案是创建一个通用枚举类,然后对其进行扩展。你可以看看这个

更新:或者,我找到了这个来自phpclasses.org。

这是一个用于处理php中的类型安全枚举的github库:

这个库处理类生成,类缓存,它实现了Type Safe Enumeration设计模式,有几个辅助方法来处理枚举,比如为枚举组合检索枚举排序或检索二进制值的序数。

生成的代码使用一个普通的旧php模板文件,该文件也是可配置的,因此您可以提供自己的模板。

这是用phpunit覆盖的完整测试。

github上的php-enums(随意分叉)

用法:(@ see usage.php,或单元测试以获取更多详细信息)

<?php
//require the library
require_once __DIR__ . '/src/Enum.func.php';

//if you don't have a cache directory, create one
@mkdir(__DIR__ . '/cache');
EnumGenerator::setDefaultCachedClassesDir(__DIR__ . '/cache');

//Class definition is evaluated on the fly:
Enum('FruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'));

//Class definition is cached in the cache directory for later usage:
Enum('CachedFruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'), '\my\company\name\space', true);

echo 'FruitsEnum::APPLE() == FruitsEnum::APPLE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::APPLE()) . "\n";

echo 'FruitsEnum::APPLE() == FruitsEnum::ORANGE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::ORANGE()) . "\n";

echo 'FruitsEnum::APPLE() instanceof Enum: ';
var_dump(FruitsEnum::APPLE() instanceof Enum) . "\n";

echo 'FruitsEnum::APPLE() instanceof FruitsEnum: ';
var_dump(FruitsEnum::APPLE() instanceof FruitsEnum) . "\n";

echo "->getName()\n";
foreach (FruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getName() . "\n";
}

echo "->getValue()\n";
foreach (FruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getValue() . "\n";
}

echo "->getOrdinal()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getOrdinal() . "\n";
}

echo "->getBinary()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getBinary() . "\n";
}

输出:

FruitsEnum::APPLE() == FruitsEnum::APPLE(): bool(true)
FruitsEnum::APPLE() == FruitsEnum::ORANGE(): bool(false)
FruitsEnum::APPLE() instanceof Enum: bool(true)
FruitsEnum::APPLE() instanceof FruitsEnum: bool(true)
->getName()
  APPLE
  ORANGE
  RASBERRY
  BANNANA
->getValue()
  apple
  orange
  rasberry
  bannana
->getValue() when values have been specified
  pig
  dog
  cat
  bird
->getOrdinal()
  1
  2
  3
  4
->getBinary()
  1
  2
  4
  8
abstract class Enumeration
{
    public static function enum() 
    {
        $reflect = new ReflectionClass( get_called_class() );
        return $reflect->getConstants();
    }
}


class Test extends Enumeration
{
    const A = 'a';
    const B = 'b';    
}


foreach (Test::enum() as $key => $value) {
    echo "$key -> $value<br>";
}

可能就像

一样简单
enum DaysOfWeek {
    Sunday,
    Monday,
    // ...
}

将来。

PHP RFC:枚举类型

我已经开始使用下面的方法,因为它使我能够为函数参数提供类型安全性,在NetBeans中自动完成并具有良好的性能。我不喜欢的一件事是你必须在定义类之后调用 [extended class name] :: enumerate();

abstract class Enum {

    private 

我已经开始使用下面的方法,因为它使我能够为函数参数提供类型安全性,在NetBeans中自动完成并具有良好的性能。我不喜欢的一件事是你必须在定义类之后调用 [extended class name] :: enumerate();

<*>value; protected function __construct($value) { $this->_value = $value; } public function __toString() { return (string) $this->_value; } public static function enumerate() { $class = get_called_class(); $ref = new ReflectionClass($class); $statics = $ref->getStaticProperties(); foreach ($statics as $name => $value) { $ref->setStaticPropertyValue($name, new $class($value)); } } } class DaysOfWeek extends Enum { public static $MONDAY = 0; public static $SUNDAY = 1; // etc. } DaysOfWeek::enumerate(); function isMonday(DaysOfWeek $d) { if ($d == DaysOfWeek::$MONDAY) { return true; } else { return false; } } $day = DaysOfWeek::$MONDAY; echo (isMonday($day) ? "bummer it's monday" : "Yay! it's not monday");

以下我的Enum课程定义为强类型,并且非常自然可供使用和定义。

<强>定义:

class Fruit extends Enum {
    static public $APPLE = 1;
    static public $ORANGE = 2;
}
Fruit::initialize(); //Can also be called in autoloader

切换枚举

$myFruit = Fruit::$APPLE;

switch ($myFruit) {
    case Fruit::$APPLE  : echo "I like apples\n";  break;
    case Fruit::$ORANGE : echo "I hate oranges\n"; break;
}

>> I like apples

传递枚举作为参数(强类型)

/** Function only accepts Fruit enums as input**/
function echoFruit(Fruit $fruit) {
    echo $fruit->getName().": ".$fruit->getValue()."\n";
}

/** Call function with each Enum value that Fruit has */
foreach (Fruit::getList() as $fruit) {
    echoFruit($fruit);
}

//Call function with Apple enum
echoFruit(Fruit::$APPLE)

//Will produce an error. This solution is strongly typed
echoFruit(2);

>> APPLE: 1
>> ORANGE: 2
>> APPLE: 1
>> Argument 1 passed to echoFruit() must be an instance of Fruit, integer given

Echo Enum as string

echo "I have an $myFruit\n";

>> I have an APPLE

按整数获取枚举

$myFruit = Fruit::getByValue(2);

echo "Now I have an $myFruit\n";

>> Now I have an ORANGE

按名称获取枚举

$myFruit = Fruit::getByName("APPLE");

echo "But I definitely prefer an $myFruit\n\n";

>> But I definitely prefer an APPLE

枚举类:

/**
 * @author Torge Kummerow
 */
class Enum {

    /**
     * Holds the values for each type of Enum
     */
    static private $list = array();

    /**
     * Initializes the enum values by replacing the number with an instance of itself
     * using reflection
     */
    static public function initialize() {
        $className = get_called_class();
        $class = new ReflectionClass($className);
        $staticProperties = $class->getStaticProperties();

        self::$list[$className] = array();

        foreach ($staticProperties as $propertyName => &$value) {
            if ($propertyName == 'list')
                continue;

            $enum = new $className($propertyName, $value);
            $class->setStaticPropertyValue($propertyName, $enum);
            self::$list[$className][$propertyName] = $enum;
        } unset($value);
    }


    /**
     * Gets the enum for the given value
     *
     * @param integer $value
     * @throws Exception
     *
     * @return Enum
     */
    static public function getByValue($value) {
        $className = get_called_class();
        foreach (self::$list[$className] as $propertyName=>&$enum) {
            /* @var $enum Enum */
            if ($enum->value == $value)
                return $enum;
        } unset($enum);

        throw new Exception("No such enum with value=$value of type ".get_called_class());
    }

    /**
     * Gets the enum for the given name
     *
     * @param string $name
     * @throws Exception
     *
     * @return Enum
     */
    static public function getByName($name) {
        $className = get_called_class();
        if (array_key_exists($name, static::$list[$className]))
            return self::$list[$className][$name];

        throw new Exception("No such enum ".get_called_class()."::\$name");
    }


    /**
     * Returns the list of all enum variants
     * @return Array of Enum
     */
    static public function getList() {
        $className = get_called_class();
        return self::$list[$className];
    }


    private $name;
    private $value;

    public function __construct($name, $value) {
        $this->name = $name;
        $this->value = $value;
    }

    public function __toString() {
        return $this->name;
    }

    public function getValue() {
        return $this->value;
    }

    public function getName() {
        return $this->name;
    }

}

<强>加成

您还可以为IDE添加注释

class Fruit extends Enum {

    /**
     * This comment is for autocomplete support in common IDEs
     * @var Fruit A yummy apple
     */
    static public $APPLE = 1;

    /**
     * This comment is for autocomplete support in common IDEs
     * @var Fruit A sour orange
     */
    static public $ORANGE = 2;
}

//This can also go to the autoloader if available.
Fruit::initialize();

我意识到这是一个非常非常老的话题,但我想到了这一点并想知道人们的想法。

注意:我正在玩这个并意识到如果我只是修改了 __ call()函数,你可以更接近实际的枚举 __ call()函数处理所有未知函数调用。所以,假设您要制作三个枚举 RED_LIGHT,YELLOW_LIGHT和GREEN_LIGHT。您现在只需执行以下操作即可:

$c->RED_LIGHT();
$c->YELLOW_LIGHT();
$c->GREEN_LIGHT();

一旦定义,您只需要再次调用它们来获取值:

echo $c->RED_LIGHT();
echo $c->YELLOW_LIGHT();
echo $c->GREEN_LIGHT();

你应该得到0,1和2.玩得开心!现在也在GitHub上了。

更新:我已经做到了,所以现在都使用 __ get() __ set()函数。这些允许您不必调用函数,除非您愿意。相反,现在你可以说:

$c->RED_LIGHT;
$c->YELLOW_LIGHT;
$c->GREEN_LIGHT;

用于创建和获取值。因为最初没有定义变量,所以调用 __ get()函数(因为没有指定值),它看到数组中的条目尚未生成。因此它进行输入,将给定的最后一个值加上一个(+1),递增最后一个值变量,然后返回TRUE。如果设置值:

$c->RED_LIGHT = 85;

然后调用 __ set()函数,然后将最后一个值设置为新值加一(+1)。所以现在我们有一个相当好的方法来做枚举,它们可以在运行中创建。

<?php
################################################################################
#   Class ENUMS
#
#       Original code by Mark Manning.
#       Copyrighted (c) 2015 by Mark Manning.
#       All rights reserved.
#
#       This set of code is hereby placed into the free software universe
#       via the GNU greater license thus placing it under the Copyleft
#       rules and regulations with the following modifications:
#
#       1. You may use this work in any other work.  Commercial or otherwise.
#       2. You may make as much money as you can with it.
#       3. You owe me nothing except to give me a small blurb somewhere in
#           your program or maybe have pity on me and donate a dollar to
#           sim_sales@paypal.com.  :-)
#
#   Blurb:
#
#       PHP Class Enums by Mark Manning (markem-AT-sim1-DOT-us).
#       Used with permission.
#
#   Notes:
#
#       VIM formatting.  Set tabs to four(4) spaces.
#
################################################################################
class enums
{
    private $enums;
    private $clear_flag;
    private $last_value;

################################################################################
#   __construct(). Construction function.  Optionally pass in your enums.
################################################################################
function __construct()
{
    $this->enums = array();
    $this->clear_flag = false;
    $this->last_value = 0;

    if( func_num_args() > 0 ){
        return $this->put( func_get_args() );
        }

    return true;
}
################################################################################
#   put(). Insert one or more enums.
################################################################################
function put()
{
    $args = func_get_args();
#
#   Did they send us an array of enums?
#   Ex: $c->put( array( "a"=>0, "b"=>1,...) );
#   OR  $c->put( array( "a", "b", "c",... ) );
#
    if( is_array($args[0]) ){
#
#   Add them all in
#
        foreach( $args[0] as $k=>$v ){
#
#   Don't let them change it once it is set.
#   Remove the IF statement if you want to be able to modify the enums.
#
            if( !isset($this->enums[$k]) ){
#
#   If they sent an array of enums like this: "a","b","c",... then we have to
#   change that to be "A"=>#. Where "#" is the current count of the enums.
#
                if( is_numeric($k) ){
                    $this->enums[$v] = $this->last_value++;
                    }
#
#   Else - they sent "a"=>"A", "b"=>"B", "c"=>"C"...
#
                    else {
                        $this->last_value = $v + 1;
                        $this->enums[$k] = $v;
                        }
                }
            }
        }
#
#   Nope!  Did they just sent us one enum?
#
        else {
#
#   Is this just a default declaration?
#   Ex: $c->put( "a" );
#
            if( count($args) < 2 ){
#
#   Again - remove the IF statement if you want to be able to change the enums.
#
                if( !isset($this->enums[$args[0]]) ){
                    $this->enums[$args[0]] = $this->last_value++;
                    }
#
#   No - they sent us a regular enum
#   Ex: $c->put( "a", "This is the first enum" );
#
                    else {
#
#   Again - remove the IF statement if you want to be able to change the enums.
#
                        if( !isset($this->enums[$args[0]]) ){
                            $this->last_value = $args[1] + 1;
                            $this->enums[$args[0]] = $args[1];
                            }
                        }
                }
            }

    return true;
}
################################################################################
#   get(). Get one or more enums.
################################################################################
function get()
{
    $num = func_num_args();
    $args = func_get_args();
#
#   Is this an array of enums request? (ie: $c->get(array("a","b","c"...)) )
#
    if( is_array($args[0]) ){
        $ary = array();
        foreach( $args[0] as $k=>$v ){
            $ary[$v] = $this->enums[$v];
            }

        return $ary;
        }
#
#   Is it just ONE enum they want? (ie: $c->get("a") )
#
        else if( ($num > 0) && ($num < 2) ){
            return $this->enums[$args[0]];
            }
#
#   Is it a list of enums they want? (ie: $c->get( "a", "b", "c"...) )
#
        else if( $num > 1 ){
            $ary = array();
            foreach( $args as $k=>$v ){
                $ary[$v] = $this->enums[$v];
                }

            return $ary;
            }
#
#   They either sent something funky or nothing at all.
#
    return false;
}
################################################################################
#   clear(). Clear out the enum array.
#       Optional.  Set the flag in the __construct function.
#       After all, ENUMS are supposed to be constant.
################################################################################
function clear()
{
    if( $clear_flag ){
        unset( $this->enums );
        $this->enums = array();
        }

    return true;
}
################################################################################
#   __call().  In case someone tries to blow up the class.
################################################################################
function __call( $name, $arguments )
{
    if( isset($this->enums[$name]) ){ return $this->enums[$name]; }
        else if( !isset($this->enums[$name]) && (count($arguments) > 0) ){
            $this->last_value = $arguments[0] + 1;
            $this->enums[$name] = $arguments[0];
            return true;
            }
        else if( !isset($this->enums[$name]) && (count($arguments) < 1) ){
            $this->enums[$name] = $this->last_value++;
            return true;
            }

    return false;
}
################################################################################
#   __get(). Gets the value.
################################################################################
function __get($name)
{
    if( isset($this->enums[$name]) ){ return $this->enums[$name]; }
        else if( !isset($this->enums[$name]) ){
            $this->enums[$name] = $this->last_value++;
            return true;
            }

    return false;
}
################################################################################
#   __set().  Sets the value.
################################################################################
function __set( $name, $value=null )
{
    if( isset($this->enums[$name]) ){ return false; }
        else if( !isset($this->enums[$name]) && !is_null($value) ){
            $this->last_value = $value + 1;
            $this->enums[$name] = $value;
            return true;
            }
        else if( !isset($this->enums[$name]) && is_null($value) ){
            $this->enums[$name] = $this->last_value++;
            return true;
            }

    return false;
}
################################################################################
#   __destruct().  Deconstruct the class.  Remove the list of enums.
################################################################################
function __destruct()
{
    unset( $this->enums );
    $this->enums = null;

    return true;
}

}
#
#   Test code
#
#   $c = new enums();
#   $c->RED_LIGHT(85);
#   $c->YELLOW_LIGHT = 23;
#   $c->GREEN_LIGHT;
#
#   echo $c->RED_LIGHT . "\n";
#   echo $c->YELLOW_LIGHT . "\n";
#   echo $c->GREEN_LIGHT . "\n";

?>

我知道这是一个旧线程,但是我看到的解决方法都没有看起来像枚举,因为几乎所有的变通办法都要求你手动为枚举项分配值,或者它要求你传递一个枚举数组功能键。所以我为此创建了自己的解决方案。

要使用我的解决方案创建一个枚举类,可以简单地在下面扩展这个Enum类,创建一堆静态变量(不需要初始化它们),并在刚好定义下面调用yourEnumClass :: init()你的枚举课。

编辑:这仅适用于php&gt; = 5.3,但它可能也可以修改为适用于旧版本     

/**
 * A base class for enums. 
 * 
 * This class can be used as a base class for enums. 
 * It can be used to create regular enums (incremental indices), but it can also be used to create binary flag values.
 * To create an enum class you can simply extend this class, and make a call to <yourEnumClass>::init() before you use the enum.
 * Preferably this call is made directly after the class declaration. 
 * Example usages:
 * DaysOfTheWeek.class.php
 * abstract class DaysOfTheWeek extends Enum{
 *      static $MONDAY = 1;
 *      static $TUESDAY;
 *      static $WEDNESDAY;
 *      static $THURSDAY;
 *      static $FRIDAY;
 *      static $SATURDAY;
 *      static $SUNDAY;
 * }
 * DaysOfTheWeek::init();
 * 
 * example.php
 * require_once("DaysOfTheWeek.class.php");
 * $today = date('N');
 * if ($today == DaysOfTheWeek::$SUNDAY || $today == DaysOfTheWeek::$SATURDAY)
 *      echo "It's weekend!";
 * 
 * Flags.class.php
 * abstract class Flags extends Enum{
 *      static $FLAG_1;
 *      static $FLAG_2;
 *      static $FLAG_3;
 * }
 * Flags::init(Enum::$BINARY_FLAG);
 * 
 * example2.php
 * require_once("Flags.class.php");
 * $flags = Flags::$FLAG_1 | Flags::$FLAG_2;
 * if ($flags & Flags::$FLAG_1)
 *      echo "Flag_1 is set";
 * 
 * @author Tiddo Langerak
 */
abstract class Enum{

    static $BINARY_FLAG = 1;
    /**
     * This function must be called to initialize the enumeration!
     * 
     * @param bool $flags If the USE_BINARY flag is provided, the enum values will be binary flag values. Default: no flags set.
     */ 
    public static function init($flags = 0){
        //First, we want to get a list of all static properties of the enum class. We'll use the ReflectionClass for this.
        $enum = get_called_class();
        $ref = new ReflectionClass($enum);
        $items = $ref->getStaticProperties();
        //Now we can start assigning values to the items. 
        if ($flags & self::$BINARY_FLAG){
            //If we want binary flag values, our first value should be 1.
            $value = 1;
            //Now we can set the values for all items.
            foreach ($items as $key=>$item){
                if (!isset($item)){                 
                    //If no value is set manually, we should set it.
                    $enum::$key = $value;
                    //And we need to calculate the new value
                    $value *= 2;
                } else {
                    //If there was already a value set, we will continue starting from that value, but only if that was a valid binary flag value.
                    //Otherwise, we will just skip this item.
                    if ($key != 0 && ($key & ($key - 1) == 0))
                        $value = 2 * $item;
                }
            }
        } else {
            //If we want to use regular indices, we'll start with index 0.
            $value = 0;
            //Now we can set the values for all items.
            foreach ($items as $key=>$item){
                if (!isset($item)){
                    //If no value is set manually, we should set it, and increment the value for the next item.
                    $enum::$key = $value;
                    $value++;
                } else {
                    //If a value was already set, we'll continue from that value.
                    $value = $item+1;
                }
            }
        }
    }
}

现在,您可以使用 SplEnum 类本机构建它。根据官方文档。

  

SplEnum提供了模拟和创建枚举对象的功能   原生于PHP。

<?php
class Month extends SplEnum {
    const __default = self::January;

    const January = 1;
    const February = 2;
    const March = 3;
    const April = 4;
    const May = 5;
    const June = 6;
    const July = 7;
    const August = 8;
    const September = 9;
    const October = 10;
    const November = 11;
    const December = 12;
}

echo new Month(Month::June) . PHP_EOL;

try {
    new Month(13);
} catch (UnexpectedValueException $uve) {
    echo $uve->getMessage() . PHP_EOL;
}
?>

请注意,它是必须安装的扩展程序,但默认情况下不可用。这是php网站本身描述的特殊类型。上面的例子来自PHP站点。

接受的答案是要走的路,实际上我正在为简单而做。提供了枚举的大多数优点(可读,快速等)。然而,缺少一个概念:类型安全。在大多数语言中,枚举也用于限制允许的值。下面是如何通过使用私有构造函数,静态实例化方法和类型检查来获取类型安全性的示例:

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

 private $intVal;
 private function __construct($intVal){
   $this->intVal = $intVal;
 }

 //static instantiation methods
 public static function MONDAY(){
   return new self(self::Monday);
 }
 //etc.
}

//function using type checking
function printDayOfWeek(DaysOfWeek $d){ //compiler can now use type checking
  // to something with $d...
}

//calling the function is safe!
printDayOfWeek(DaysOfWeek::MONDAY());

我们甚至可以走得更远:在DaysOfWeek类中使用常量可能会导致误用:例如:一个人可能错误地以这种方式使用它:

printDayOfWeek(DaysOfWeek::Monday); //triggers a compiler error.

这是错误的(调用整数常量)。我们可以使用私有静态变量而不是常量来防止这种情况:

class DaysOfWeeks{

  private static $monday = 1;
  //etc.

  private $intVal;
  //private constructor
  private function __construct($intVal){
    $this->intVal = $intVal;
  }

  //public instantiation methods
  public static function MONDAY(){
    return new self(self::$monday);
  }
  //etc.


  //convert an instance to its integer value
  public function intVal(){
    return $this->intVal;
  }

}

当然,不可能访问整数常量(这实际上是目的)。 intVal方法允许将DaysOfWeek对象转换为其整数表示。

请注意,我们甚至可以通过在实例化方法中实现缓存机制来进一步节省内存,以便广泛使用枚举...

希望这会有所帮助

一些很好的解决方案就在这里!

这是我的版本。

  • 它强类型
  • 它的工作与IDE自完成
  • 枚举定义的代码和描述,那里的代码可以是一个整数,二进制的价值,短串,或基本上任何你想要的东西。该模式可以很容易地延伸到支助其他特性。
  • 它asupports值(==)和基准(===)比较和工作在切换的发言。

我认为主要的缺点是,这枚举的成员必须单独声明和实例,由于描述和PHP无法建造物体的静态部件的宣言的时间。我猜测一个方面这可能是使用反思与分析doc的评论代替。

抽象enum看起来是这样的:

<?php

abstract class AbstractEnum
{
    /** @var array cache of all enum instances by class name and integer value */
    private static $allEnumMembers = array();

    /** @var mixed */
    private $code;

    /** @var string */
    private $description;

    /**
     * Return an enum instance of the concrete type on which this static method is called, assuming an instance
     * exists for the passed in value.  Otherwise an exception is thrown.
     *
     * @param $code
     * @return AbstractEnum
     * @throws Exception
     */
    public static function getByCode($code)
    {
        $concreteMembers = &self::getConcreteMembers();

        if (array_key_exists($code, $concreteMembers)) {
            return $concreteMembers[$code];
        }

        throw new Exception("Value '$code' does not exist for enum '".get_called_class()."'");
    }

    public static function getAllMembers()
    {
        return self::getConcreteMembers();
    }

    /**
     * Create, cache and return an instance of the concrete enum type for the supplied primitive value.
     *
     * @param mixed $code code to uniquely identify this enum
     * @param string $description
     * @throws Exception
     * @return AbstractEnum
     */
    protected static function enum($code, $description)
    {
        $concreteMembers = &self::getConcreteMembers();

        if (array_key_exists($code, $concreteMembers)) {
            throw new Exception("Value '$code' has already been added to enum '".get_called_class()."'");
        }

        $concreteMembers[$code] = $concreteEnumInstance = new static($code, $description);

        return $concreteEnumInstance;
    }

    /**
     * @return AbstractEnum[]
     */
    private static function &getConcreteMembers() {
        $thisClassName = get_called_class();

        if (!array_key_exists($thisClassName, self::$allEnumMembers)) {
            $concreteMembers = array();
            self::$allEnumMembers[$thisClassName] = $concreteMembers;
        }

        return self::$allEnumMembers[$thisClassName];
    }

    private function __construct($code, $description)
    {
        $this->code = $code;
        $this->description = $description;
    }

    public function getCode()
    {
        return $this->code;
    }

    public function getDescription()
    {
        return $this->description;
    }
}

这是一个实例的具体枚举:

<?php

require('AbstractEnum.php');

class EMyEnum extends AbstractEnum
{
    /** @var EMyEnum */
    public static $MY_FIRST_VALUE;
    /** @var EMyEnum */
    public static $MY_SECOND_VALUE;
    /** @var EMyEnum */
    public static $MY_THIRD_VALUE;

    public static function _init()
    {
        self::$MY_FIRST_VALUE = self::enum(1, 'My first value');
        self::$MY_SECOND_VALUE = self::enum(2, 'My second value');
        self::$MY_THIRD_VALUE = self::enum(3, 'My third value');
    }
}

EMyEnum::_init();

它可以用这样的:

<?php

require('EMyEnum.php');

echo EMyEnum::$MY_FIRST_VALUE->getCode().' : '.EMyEnum::$MY_FIRST_VALUE->getDescription().PHP_EOL.PHP_EOL;

var_dump(EMyEnum::getAllMembers());

echo PHP_EOL.EMyEnum::getByCode(2)->getDescription().PHP_EOL;

和生产这种产出:

1:我的第一个价值

array(3){
[1]=>
目(EMyEnum)#1(2){
["代码":"AbstractEnum":私人]=>
int(1)
["description":"AbstractEnum":私人]=>
string(14)"我的第一个价值"
}
[2]=>
目(EMyEnum)#2(2){
["代码":"AbstractEnum":私人]=>
int(2)
["description":"AbstractEnum":私人]=>
string(15)"我的第二个值"
}
[3]=>
目(EMyEnum)#3(2){
["代码":"AbstractEnum":私人]=>
int(3)
["description":"AbstractEnum":私人]=>
string(14)"我的第三值"
}
}

我的第二个值

class DayOfWeek {
    static $values = array(
        self::MONDAY,
        self::TUESDAY,
        // ...
    );

    const MONDAY  = 0;
    const TUESDAY = 1;
    // ...
}

$today = DayOfWeek::MONDAY;

// If you want to check if a value is valid
assert( in_array( $today, DayOfWeek::$values ) );

不要使用反射。这使得你很难推理你的代码并追踪正在使用的东西,并且往往会破坏静态分析工具(例如你的IDE中内置的东西)。

这里的一些其他答案中缺少的一个方面是使用带有类型提示的枚举的方法。

如果将枚举定义为抽象类中的一组常量,例如

abstract class ShirtSize {
    public const SMALL = 1;
    public const MEDIUM = 2;
    public const LARGE = 3;
}

然后你不能在函数参数中输入提示 - 对于一个,因为它不是可实例化的,而且因为 ShirtSize :: SMALL 的类型是 int ,而不是 ShirtSize

这就是为什么PHP中的原生枚举会比我们想出的任何东西都好得多。但是,我们可以通过保持表示枚举值的私有属性来近似枚举,然后将此属性的初始化限制为我们预定义的常量。为了防止枚举被任意实例化(没有类型检查白名单的开销),我们将构造函数设为私有。

class ShirtSize {
    private $size;
    private function __construct ($size) {
        $this->size = $size;
    }
    public function equals (ShirtSize $s) {
        return $this->size === $s->size;
    }
    public static function SMALL () { return new self(1); }
    public static function MEDIUM () { return new self(2); }
    public static function LARGE () { return new self(3); }
}

然后我们可以像这样使用 ShirtSize

function sizeIsAvailable ($productId, ShirtSize $size) {
    // business magic
}
if(sizeIsAvailable(

这里的一些其他答案中缺少的一个方面是使用带有类型提示的枚举的方法。

如果将枚举定义为抽象类中的一组常量,例如

abstract class ShirtSize {
    public const SMALL = 1;
    public const MEDIUM = 2;
    public const LARGE = 3;
}

然后你不能在函数参数中输入提示 - 对于一个,因为它不是可实例化的,而且因为 ShirtSize :: SMALL 的类型是 int ,而不是 ShirtSize

这就是为什么PHP中的原生枚举会比我们想出的任何东西都好得多。但是,我们可以通过保持表示枚举值的私有属性来近似枚举,然后将此属性的初始化限制为我们预定义的常量。为了防止枚举被任意实例化(没有类型检查白名单的开销),我们将构造函数设为私有。

class ShirtSize {
    private $size;
    private function __construct ($size) {
        $this->size = $size;
    }
    public function equals (ShirtSize $s) {
        return $this->size === $s->size;
    }
    public static function SMALL () { return new self(1); }
    public static function MEDIUM () { return new self(2); }
    public static function LARGE () { return new self(3); }
}

然后我们可以像这样使用 ShirtSize

<*>

这样,与用户的观点最大的区别在于你必须使用常量名称上的()

但有一个缺点是当 == 返回true时, === (比较对象相等)将返回false。因此,最好提供 equals 方法,以便用户不必记住使用 == 而不是 === 比较两个枚举值。

编辑:现有的几个答案非常相似,特别是: https://stackoverflow.com/a/25526473/2407870

GET["id"], ShirtSize::LARGE())) { echo "Available"; } else { echo "Out of stock."; } $s2 = ShirtSize::SMALL(); $s3 = ShirtSize::MEDIUM(); echo $s2->equals($s3) ? "SMALL == MEDIUM" : "SMALL != MEDIUM";

这样,与用户的观点最大的区别在于你必须使用常量名称上的()

但有一个缺点是当 == 返回true时, === (比较对象相等)将返回false。因此,最好提供 equals 方法,以便用户不必记住使用 == 而不是 === 比较两个枚举值。

编辑:现有的几个答案非常相似,特别是: https://stackoverflow.com/a/25526473/2407870

踩到@Brian Cline的答案,我以为我可以给我5美分

<?php 
/**
 * A class that simulates Enums behaviour
 * <code>
 * class Season extends Enum{
 *    const Spring  = 0;
 *    const Summer = 1;
 *    const Autumn = 2;
 *    const Winter = 3;
 * }
 * 
 * $currentSeason = new Season(Season::Spring);
 * $nextYearSeason = new Season(Season::Spring);
 * $winter = new Season(Season::Winter);
 * $whatever = new Season(-1);               // Throws InvalidArgumentException
 * echo $currentSeason.is(Season::Spring);   // True
 * echo $currentSeason.getName();            // 'Spring'
 * echo $currentSeason.is($nextYearSeason);  // True
 * echo $currentSeason.is(Season::Winter);   // False
 * echo $currentSeason.is(Season::Spring);   // True
 * echo $currentSeason.is($winter);          // False
 * </code>
 * 
 * Class Enum
 * 
 * PHP Version 5.5
 */
abstract class Enum
{
    /**
     * Will contain all the constants of every enum that gets created to 
     * avoid expensive ReflectionClass usage
     * @var array
     */
    private static 

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>constCacheArray = []; /** * The value that separates this instance from the rest of the same class * @var mixed */ private

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>value; /** * The label of the Enum instance. Will take the string name of the * constant provided, used for logging and human readable messages * @var string */ private

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>name; /** * Creates an enum instance, while makes sure that the value given to the * enum is a valid one * * @param mixed $value The value of the current * * @throws \InvalidArgumentException */ public final function __construct($value) { $constants = self::_getConstants(); if (count($constants) !== count(array_unique($constants))) { throw new \InvalidArgumentException('Enums cannot contain duplicate constant values'); } if ($name = array_search($value, $constants)) { $this->_value = $value; $this->_name = $name; } else { throw new \InvalidArgumentException('Invalid enum value provided'); } } /** * Returns the constant name of the current enum instance * * @return string */ public function getName() { return $this->_name; } /** * Returns the value of the current enum instance * * @return mixed */ public function getValue() { return $this->_value; } /** * Checks whether this enum instance matches with the provided one. * This function should be used to compare Enums at all times instead * of an identity comparison * <code> * // Assuming EnumObject and EnumObject2 both extend the Enum class * // and constants with such values are defined * $var = new EnumObject('test'); * $var2 = new EnumObject('test'); * $var3 = new EnumObject2('test'); * $var4 = new EnumObject2('test2'); * echo $var->is($var2); // true * echo $var->is('test'); // true * echo $var->is($var3); // false * echo $var3->is($var4); // false * </code> * * @param mixed|Enum $enum The value we are comparing this enum object against * If the value is instance of the Enum class makes * sure they are instances of the same class as well, * otherwise just ensures they have the same value * * @return bool */ public final function is($enum) { // If we are comparing enums, just make // sure they have the same toString value if (is_subclass_of($enum, __CLASS__)) { return get_class($this) === get_class($enum) && $this->getValue() === $enum->getValue(); } else { // Otherwise assume $enum is the value we are comparing against // and do an exact comparison return $this->getValue() === $enum; } } /** * Returns the constants that are set for the current Enum instance * * @return array */ private static function _getConstants() { if (self::

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>constCacheArray == null) { self::

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>constCacheArray = []; } $calledClass = get_called_class(); if (!array_key_exists($calledClass, self::

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>constCacheArray)) { $reflect = new \ReflectionClass($calledClass); self::

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>constCacheArray[$calledClass] = $reflect->getConstants(); } return self::

踩到@Brian Cline的答案,我以为我可以给我5美分

<*>constCacheArray[$calledClass]; } }

这是我对“动态”的看法。枚举...所以我可以用变量调用它,例如。从形式。

查看此代码块下方的更新版本...

$value = "concert";
$Enumvalue = EnumCategory::enum($value);
//$EnumValue = 1

class EnumCategory{
    const concert = 1;
    const festival = 2;
    const sport = 3;
    const nightlife = 4;
    const theatre = 5;
    const musical = 6;
    const cinema = 7;
    const charity = 8;
    const museum = 9;
    const other = 10;

    public function enum($string){
        return constant('EnumCategory::'.$string);
    }
}

更新:更好的方式......

class EnumCategory {

    static $concert = 1;
    static $festival = 2;
    static $sport = 3;
    static $nightlife = 4;
    static $theatre = 5;
    static $musical = 6;
    static $cinema = 7;
    static $charity = 8;
    static $museum = 9;
    static $other = 10;

}

使用

进行通话
EnumCategory::${$category};

昨天我在我的博客上写了这一课程 。我认为在php脚本中使用它可能很容易:

final class EnumException extends Exception{}

abstract class Enum
{
    /**
     * @var array ReflectionClass
     */
    protected static $reflectorInstances = array();
    /**
     * Массив конфигурированного объекта-константы enum
     * @var array
     */
    protected static $enumInstances = array();
    /**
     * Массив соответствий значение->ключ используется для проверки - 
     * если ли константа с таким значением
     * @var array
     */
    protected static $foundNameValueLink = array();

    protected $constName;
    protected $constValue;

    /**
     * Реализует паттерн "Одиночка"
     * Возвращает объект константы, но но как объект его использовать не стоит, 
     * т.к. для него реализован "волшебный метод" __toString()
     * Это должно использоваться только для типизачии его как параметра
     * @paradm Node
     */
    final public static function get($value)
    {
        // Это остается здесь для увеличения производительности (по замерам ~10%)
        $name = self::getName($value);
        if ($name === false)
            throw new EnumException("Неизвестая константа");
        $className = get_called_class();    
        if (!isset(self::$enumInstances[$className][$name]))
        {
            $value = constant($className.'::'.$name);
            self::$enumInstances[$className][$name] = new $className($name, $value);
        }

        return self::$enumInstances[$className][$name];
    }

    /**
     * Возвращает массив констант пар ключ-значение всего перечисления
     * @return array 
     */
    final public static function toArray()
    {
        $classConstantsArray = self::getReflectorInstance()->getConstants();
        foreach ($classConstantsArray as $k => $v)
            $classConstantsArray[$k] = (string)$v;
        return $classConstantsArray;
    }

    /**
     * Для последующего использования в toArray для получения массива констант ключ->значение 
     * @return ReflectionClass
     */
    final private static function getReflectorInstance()
    {
        $className = get_called_class();
        if (!isset(self::$reflectorInstances[$className]))
        {
            self::$reflectorInstances[$className] = new ReflectionClass($className);
        }
        return self::$reflectorInstances[$className];
    }

    /**
     * Получает имя константы по её значению
     * @param string $value
     */
    final public static function getName($value)
    {
        $className = (string)get_called_class();

        $value = (string)$value;
        if (!isset(self::$foundNameValueLink[$className][$value]))
        {
            $constantName = array_search($value, self::toArray(), true);
            self::$foundNameValueLink[$className][$value] = $constantName;
        }
        return self::$foundNameValueLink[$className][$value];
    }

    /**
     * Используется ли такое имя константы в перечислении
     * @param string $name
     */
    final public static function isExistName($name)
    {
        $constArray = self::toArray();
        return isset($constArray[$name]);
    }

    /**
     * Используется ли такое значение константы в перечислении
     * @param string $value
     */
    final public static function isExistValue($value)
    {
        return self::getName($value) === false ? false : true;
    }   


    final private function __clone(){}

    final private function __construct($name, $value)
    {
        $this->constName = $name;
        $this->constValue = $value;
    }

    final public function __toString()
    {
        return (string)$this->constValue;
    }
}

用法:

class enumWorkType extends Enum
{
        const FULL = 0;
        const SHORT = 1;
}

指出解决方案效果很好。干净,光滑。

但是,如果您想要强类型枚举,可以使用:

class TestEnum extends Enum
{
    public static $TEST1;
    public static $TEST2;
}
TestEnum::init(); // Automatically initializes enum values

Enum类看起来像:

class Enum
{
    public static function parse($enum)
    {
        $class = get_called_class();
        $vars = get_class_vars($class);
        if (array_key_exists($enum, $vars)) {
            return $vars[$enum];
        }
        return null;
    }

    public static function init()
    {
        $className = get_called_class();
        $consts = get_class_vars($className);
        foreach ($consts as $constant => $value) {
            if (is_null($className::$constant)) {
                $constantValue = $constant;
                $constantValueName = $className . '::' . $constant . '_VALUE';
                if (defined($constantValueName)) {
                    $constantValue = constant($constantValueName);
                }
                $className::$constant = new $className($constantValue);
            }
        }
    }

    public function __construct($value)
    {
        $this->value = $value;
    }
}

这样,枚举值是强类型的

TestEnum :: $ TEST1 === TestEnum :: parse('TEST1')// true statement

我根据Brian Cline的答案创建了一个库,名为 greg0ire / enum 享受!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top