Pregunta

Sé que PHP no tiene enumeraciones nativas. Pero me he acostumbrado a ellos desde el mundo de Java. Me encantaría usar las enumeraciones como una forma de dar valores predefinidos que las funciones de finalización automática de IDE podrían entender.

Las constantes hacen el truco, pero existe el problema de colisión en el espacio de nombres y (o en realidad porque ) son globales. Los arreglos no tienen el problema del espacio de nombres, pero son demasiado vagos, se pueden sobrescribir en tiempo de ejecución y los IDE rara vez (¿nunca?) Saben cómo rellenar automáticamente sus claves.

¿Hay alguna solución / solución que usas comúnmente? ¿Alguien recuerda si los chicos de PHP han tenido alguna idea o decisión en torno a las enumeraciones?

¿Fue útil?

Solución

Dependiendo del caso de uso, normalmente usaría algo simple como el siguiente:

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

$today = DaysOfWeek::Sunday;

Sin embargo, otros casos de uso pueden requerir más validación de constantes y valores. Basado en los comentarios a continuación sobre la reflexión y en algunas otras notas , aquí hay un ejemplo ampliado que puede servir mejor a un rango mucho más amplio. de casos:

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);
    }
}

Al crear una clase de enumeración simple que amplía BasicEnum, ahora tiene la capacidad de usar métodos para la validación de entrada simple:

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

Como nota al margen, cada vez que uso la reflexión al menos una vez en una clase estática / constante en la que los datos no cambiarán (como en una enumeración), guardo los resultados de esos llamadas de reflexión, ya que el uso de objetos de reflexión nuevos cada vez tendrá un impacto notable en el rendimiento (almacenado en una matriz asociativa para múltiples enumeraciones).

Ahora que la mayoría de las personas han actualizado finalmente a al menos 5.3, y SplEnum está disponible, esa es ciertamente una opción viable, siempre y cuando no la tenga. No importa la noción tradicionalmente poco intuitiva de tener enumeración real instanciaciones a lo largo de su base de código. En el ejemplo anterior, BasicEnum y DaysOfWeek no se pueden crear instancias en absoluto, ni deberían serlo.

Otros consejos

También hay una extensión nativa. El SplEnum

  

SplEnum ofrece la capacidad de emular y crear objetos de enumeración.   nativamente en PHP.

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

¿Qué pasa con las constantes de clase?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

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

echo YourClass::SOME_CONSTANT;

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

La respuesta superior es fantástica. Sin embargo, si lo lo extiende de dos maneras diferentes, entonces la extensión que se haga primero resultará en una llamada a las funciones que creará el caché. Esta memoria caché será utilizada por todas las llamadas subsiguientes, sin importar la extensión en la que se inicien las llamadas ...

Para resolver esto, reemplace la variable y la primera función con:

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];
}

Uso interface en lugar de class :

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

var $today = DaysOfWeek::Sunday;

Utilicé clases con constantes:

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

print Enum::NAME;

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

final class TestEnum
{

    private static 

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

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

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

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

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

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

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

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

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

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

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

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

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

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

He comentado algunas de las otras respuestas aquí, así que pensé que yo también sopesaría. Al final del día, dado que PHP no es compatible con las enumeraciones de tipo, puede hacerlo de dos maneras: eliminar las enumeraciones de tipo o vivir con el hecho de que son extremadamente difíciles de eliminar de manera efectiva.

Prefiero vivir con el hecho y, en cambio, usar el método const que otras respuestas aquí han usado de una u otra forma:

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());
    }

}

Un ejemplo de enumeración:

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;

}

El uso de Enum como clase base a partir de la cual se extienden todas las demás enumeraciones permite métodos de ayuda, como toArray , isValid , etc. . Para mí, las enumeraciones escritas ( y la gestión de sus instancias ) terminan demasiado desordenadas.


Hipotético

Si existía un método mágico __getStatic ( y preferiblemente un método mágico __equals también ) gran parte de esto podría ser mitigado con una especie de patrón multiton.

( Lo siguiente es hipotético; no funcionará , aunque quizás algún día lo haga )

<*>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

Bueno, para un java simple como enum en php, uso:

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];
    }
}

Y para llamarlo:

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

Pero soy un principiante de PHP, luchando con la sintaxis por lo que esta podría no ser la mejor manera. Experimenté algunas con Constantes de clase, usar Reflexión para obtener el nombre de la constante de su valor, podría ser mejor.

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

abstract class TypedEnum
{
    private static 

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

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); }      
}

Ejemplo Enum:

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');

Ejemplo de uso:

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

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

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

También puede usarlo dentro de una declaración de cambio:

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

También puede crear una entrada de enumeración por nombre o valor:

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

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

<*>instancedValues; private

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

<*>value; private

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

<*>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::

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

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

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

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

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

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

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

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

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

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

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

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

Cuatro años más tarde me encontré con esto otra vez. Mi enfoque actual es este, ya que permite completar el código en el IDE, así como el tipo de seguridad:

Clase base:

<*>

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

<*>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; } }

Ejemplo Enum:

<*>

Ejemplo de uso:

<*>

Tenga en cuenta que todas las instancias de la misma entrada de enumeración son las mismas:

<*>

También puede usarlo dentro de una declaración de cambio:

<*>

También puede crear una entrada de enumeración por nombre o valor:

<*>

O simplemente puede obtener el nombre (es decir, el nombre de la función) de una entrada de enumeración existente:

<*>

Si necesita usar enumeraciones que son únicas a nivel mundial (es decir, incluso cuando se comparan elementos entre diferentes enumeraciones) y son fáciles de usar, no dude en utilizar el siguiente código. También agregué algunos métodos que me parecen útiles. Encontrará ejemplos en los comentarios en la parte superior del código.

<?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 

Si necesita usar enumeraciones que son únicas a nivel mundial (es decir, incluso cuando se comparan elementos entre diferentes enumeraciones) y son fáciles de usar, no dude en utilizar el siguiente código. También agregué algunos métodos que me parecen útiles. Encontrará ejemplos en los comentarios en la parte superior del código.

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

Si necesita usar enumeraciones que son únicas a nivel mundial (es decir, incluso cuando se comparan elementos entre diferentes enumeraciones) y son fáciles de usar, no dude en utilizar el siguiente código. También agregué algunos métodos que me parecen útiles. Encontrará ejemplos en los comentarios en la parte superior del código.

<*>) { // 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"; } } ?>

También me gustan los enums de java y por esta razón escribo mis enums de esta manera, creo que este es el comportamiento más similar como en los enums de Java, por supuesto, si algunos quieren usar más métodos de java deberían escribirlo aquí. , o en clase abstracta, pero la idea central está incrustada en el código a continuación


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

Encontré esta biblioteca en github y creo que ofrece una alternativa muy adecuada a las respuestas aquí.

Implementación de PHP Enum inspirada en SplEnum

  • Puede escribir una sugerencia: function setAction (Action $ action) {
  • Puede enriquecer la enumeración con métodos (por ejemplo, format , parse ,…)
  • Puede extender la enumeración para agregar nuevos valores (haga su enumeración final para evitarlo)
  • Puede obtener una lista de todos los valores posibles (ver más abajo)

Declaración

<?php
use MyCLabs\Enum\Enum;

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

Uso

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

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

valores de enumeración de sugerencia de tipo:

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

La solución más común que he visto enumeración en PHP ha sido crear una clase de enumeración genérica y luego extenderla. Puede consultar esto .

ACTUALIZACIÓN: Alternativamente, encontré esto de phpclasses.org.

Aquí hay una biblioteca github para manejar enumeraciones seguras de tipos en php:

Esta biblioteca maneja la generación de clases, el almacenamiento en caché de clases e implementa el patrón de diseño de Type Safe Enumeration, con varios métodos de ayuda para tratar las enumeraciones, como recuperar un ordinal para clasificar las enumeraciones, o recuperar un valor binario, para combinaciones de enumeraciones.

El código generado utiliza un archivo de plantilla php antiguo, que también es configurable, para que puedas proporcionar tu propia plantilla.

Es prueba completa cubierta con phpunit.

php-enums en github (siéntete libre de bifurcar)

Uso: (@see use.php, o pruebas de unidad para más detalles)

<?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";
}

Salida:

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>";
}

Puede ser tan simple como

enum DaysOfWeek {
    Sunday,
    Monday,
    // ...
}

en el futuro.

RFC de PHP: tipos enumerados

He seguido el siguiente enfoque, ya que me da la posibilidad de tener seguridad de tipo para los parámetros de función, autocompletar en NetBeans y un buen rendimiento. Lo único que no me gusta demasiado es que tienes que llamar [nombre de clase extendido] :: enumerate (); después de definir la clase.

abstract class Enum {

    private 

He seguido el siguiente enfoque, ya que me da la posibilidad de tener seguridad de tipo para los parámetros de función, autocompletar en NetBeans y un buen rendimiento. Lo único que no me gusta demasiado es que tienes que llamar [nombre de clase extendido] :: enumerate (); después de definir la clase.

<*>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");

La definición de la clase de Mi Enum a continuación es Escrito con fuerza y muy natural para usar y definir.

Definition:

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

Cambiar a Enumeración

$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

Pase Enum como parámetro (Escrito con fuerza)

/** 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

Obtener Enum por entero

$myFruit = Fruit::getByValue(2);

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

>> Now I have an ORANGE

Obtener enumeración por nombre

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

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

>> But I definitely prefer an APPLE

La clase Enum:

/**
 * @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;
    }

}

Adición

Por supuesto, también puede agregar comentarios para 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();

Me doy cuenta de que este es un hilo muy, muy, muy viejo, pero pensé en esto y quise saber qué pensaba la gente.

Notas: estaba jugando un poco con esto y me di cuenta de que si acababa de modificar la función __call () , puede acercarme aún más a las enums reales. La función __call () maneja todas las llamadas de función desconocidas. Así que digamos que quieres hacer tres enums RED_LIGHT, YELLOW_LIGHT y GREEN_LIGHT. Puede hacerlo ahora haciendo lo siguiente:

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

Una vez definido, todo lo que tienes que hacer es llamarlos nuevamente para obtener los valores:

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

y debes obtener 0, 1 y 2. ¡Diviértete! Esto también está ahora en GitHub.

Actualización: Lo hice para que ahora se utilicen las funciones __get () y __set () . Esto le permite no tener que llamar a una función a menos que desee. En su lugar, ahora solo puedes decir:

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

Tanto para la creación como para la obtención de los valores. Debido a que las variables no se han definido inicialmente, se llama a la función __get () (porque no hay un valor especificado) que vea que la entrada en la matriz no se ha realizado. Así que hace la entrada, le asigna el último valor dado más uno (+1), incrementa la última variable de valor y devuelve VERDADERO. Si establece el valor:

$c->RED_LIGHT = 85;

Luego se llama a la función __set () y el último valor se establece en el nuevo valor más uno (+1). Así que ahora tenemos una forma bastante buena de hacer enumeraciones y se pueden crear sobre la marcha.

<?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";

?>

Sé que este es un hilo antiguo, sin embargo, ninguna de las soluciones que he visto realmente parecían enumeración, ya que casi todas las soluciones requieren que asignes valores manualmente a los elementos de la enumeración, o requiere que pases una serie de enumeración Claves para una función. Así que creé mi propia solución para esto.

Para crear una clase de enumeración usando mi solución, simplemente puede extender esta clase de enumeración a continuación, crear un grupo de variables estáticas (no es necesario inicializarlas) y realizar una llamada a yourEnumClass :: init () justo debajo de la definición de su clase de enumeración

editar: esto solo funciona en php > = 5.3, pero probablemente también se puede modificar para que funcione en versiones anteriores     

/**
 * 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;
                }
            }
        }
    }
}

Ahora puedes usar la clase SplEnum para construirla de forma nativa. Según la documentación oficial.

  

SplEnum ofrece la capacidad de emular y crear objetos de enumeración.   nativamente en 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;
}
?>

Tenga en cuenta que es una extensión que se debe instalar, pero no está disponible de forma predeterminada. Lo que se incluye en Tipos especiales que se describe en el propio sitio web de php. El ejemplo anterior se toma del sitio PHP.

La respuesta aceptada es el camino a seguir y en realidad es lo que estoy haciendo para simplificar. Se ofrecen la mayoría de las ventajas de la enumeración (legibles, rápidas, etc.). Falta un concepto, sin embargo: tipo de seguridad. En la mayoría de los idiomas, las enumeraciones también se utilizan para restringir los valores permitidos. A continuación se muestra un ejemplo de cómo la seguridad de tipos también se puede obtener mediante el uso de constructores privados, métodos de creación de instancias estáticas y verificación de tipos:

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());

Incluso podríamos ir más lejos: el uso de constantes en la clase DaysOfWeek podría llevar a un uso incorrecto: por ejemplo, Se podría usar erróneamente de esta manera:

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

que es incorrecto (llama constante de entero). Podemos evitar esto utilizando variables estáticas privadas en lugar de constantes:

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;
  }

}

Por supuesto, no es posible acceder a constantes enteras (este fue el propósito). El método intVal permite convertir un objeto DaysOfWeek a su representación entera.

Tenga en cuenta que incluso podríamos ir más lejos mediante la implementación de un mecanismo de almacenamiento en caché en los métodos de creación de instancias para ahorrar memoria en caso de que las enumeraciones se utilicen ampliamente ...

Espero que esto ayude

¡Algunas buenas soluciones aquí!

Aquí está mi versión.

  • Está fuertemente tipado
  • Funciona con IDE autocompletado
  • Las enumeraciones se definen mediante un código y una descripción, donde el código puede ser un número entero, un valor binario, una cadena corta o básicamente cualquier otra cosa que desee. El patrón podría extenderse fácilmente para admitir otras propiedades.
  • Admite comparaciones de valor (==) y de referencia (===) y funciona en sentencias de cambio.

Creo que la principal desventaja es que los miembros de la enumeración tienen que declararse e instanciarse por separado, debido a las descripciones y la incapacidad de PHP para construir objetos en el momento de la declaración estática de miembros. Supongo que una forma de evitar esto podría ser utilizar la reflexión con comentarios de documentos analizados en su lugar.

La enumeración abstracta se ve así:

<?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;
    }
}

Aquí hay un ejemplo de enumeración concreta:

<?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();

Que se puede utilizar así:

<?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;

Y produce esta salida:

  

1: Mi primer valor

     

array (3) {
       [1] = >
       object (EMyEnum) # 1 (2) {
         [" código ": " AbstractEnum ": private] = >
         int (1)
         [" descripción ": " AbstractEnum ": private] = >
         cadena (14) " Mi primer valor "
       }
       [2] = >
       object (EMyEnum) # 2 (2) {
         [" código ": " AbstractEnum ": private] = >
         int (2)
         [" descripción ": " AbstractEnum ": private] = >
         cadena (15) " Mi segundo valor "
       }
       [3] = >
       object (EMyEnum) # 3 (2) {
         [" código ": " AbstractEnum ": private] = >
         int (3)
         [" descripción ": " AbstractEnum ": private] = >
         cadena (14) " Mi tercer valor "
       }
     }

     

Mi segundo valor

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 ) );

No uses la reflexión. Hace que sea extremadamente difícil razonar sobre su código y rastrear dónde se está utilizando algo, y tiende a romper las herramientas de análisis estático (por ejemplo, lo que está integrado en su IDE).

Uno de los aspectos que faltan en algunas de las otras respuestas aquí es una forma de utilizar enumeraciones con sugerencias de tipo.

Si define su enumeración como un conjunto de constantes en una clase abstracta, por ejemplo,

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

entonces no puede escribirlo en un parámetro de función, por ejemplo, porque no es instanciable, sino también porque el tipo de ShirtSize :: SMALL es int , no ShirtSize .

Es por eso que las enumeraciones nativas en PHP serían mucho mejores que cualquier otra cosa que podamos encontrar. Sin embargo, podemos aproximar una enumeración manteniendo una propiedad privada que representa el valor de la enumeración, y luego restringiendo la inicialización de esta propiedad a nuestras constantes predefinidas. Para evitar que la enumeración se cree una instancia arbitraria (sin la sobrecarga de la comprobación de tipos de una lista blanca), hacemos que el constructor sea privado.

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); }
}

Entonces podemos usar ShirtSize de esta manera:

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

Uno de los aspectos que faltan en algunas de las otras respuestas aquí es una forma de utilizar enumeraciones con sugerencias de tipo.

Si define su enumeración como un conjunto de constantes en una clase abstracta, por ejemplo,

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

entonces no puede escribirlo en un parámetro de función, por ejemplo, porque no es instanciable, sino también porque el tipo de ShirtSize :: SMALL es int , no ShirtSize .

Es por eso que las enumeraciones nativas en PHP serían mucho mejores que cualquier otra cosa que podamos encontrar. Sin embargo, podemos aproximar una enumeración manteniendo una propiedad privada que representa el valor de la enumeración, y luego restringiendo la inicialización de esta propiedad a nuestras constantes predefinidas. Para evitar que la enumeración se cree una instancia arbitraria (sin la sobrecarga de la comprobación de tipos de una lista blanca), hacemos que el constructor sea privado.

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); }
}

Entonces podemos usar ShirtSize de esta manera:

<*>

De esta manera, la mayor diferencia con respecto a la perspectiva del usuario es que debe ingresar un () en el nombre de la constante.

Sin embargo, una desventaja es que === (que compara la igualdad de objetos) devolverá false cuando == devuelva true. Por esa razón, es mejor proporcionar un método es igual a , para que los usuarios no tengan que recordar usar == y no === para comparar dos valores de enumeración.

EDIT: algunas de las respuestas existentes son muy similares, en particular: 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";

De esta manera, la mayor diferencia con respecto a la perspectiva del usuario es que debe ingresar un () en el nombre de la constante.

Sin embargo, una desventaja es que === (que compara la igualdad de objetos) devolverá false cuando == devuelva true. Por esa razón, es mejor proporcionar un método es igual a , para que los usuarios no tengan que recordar usar == y no === para comparar dos valores de enumeración.

EDIT: algunas de las respuestas existentes son muy similares, en particular: https://stackoverflow.com/a/25526473/2407870 .

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

<?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 

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

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

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

<*>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

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

<*>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::

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

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

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

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

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

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

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

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

Pisando la respuesta de @Brian Cline, pensé que podría dar mis 5 centavos

<*>constCacheArray[$calledClass]; } }

Esta es mi versión de " dinámica " enumeración ... para que pueda llamarlo con variables, ej. desde un formulario.

mira la versión actualizada debajo de este bloque de código ...

$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);
    }
}

ACTUALIZACIÓN: Mejor manera de hacerlo ...

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;

}

Llamar con

EnumCategory::${$category};

Ayer escribí esta clase en mi blog . Creo que tal vez sea fácil de usar en scripts 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;
    }
}

Uso:

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

La solución señalada funciona bien. Limpio y suave.

Sin embargo, si quieres enumeración con tipos, puedes usar esto:

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

Con una clase Enum parecida a:

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;
    }
}

De esta manera, los valores de enumeración se escriben con fuerza y ??

TestEnum :: $ TEST1 === TestEnum :: parse ('TEST1') // declaración verdadera

Hice una biblioteca basada en la respuesta de Brian Cline, se llama greg0ire / enum ¡Disfruta!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top