Domanda

So che PHP non ha enumerazioni native. Ma mi sono abituato a loro dal mondo Java. Mi piacerebbe usare enum come un modo per fornire valori predefiniti che le funzionalità di completamento automatico degli IDE potrebbero comprendere.

Le costanti fanno il trucco, ma c'è il problema di collisione dello spazio dei nomi e (o in realtà perché ) sono globali. Le matrici non hanno il problema dello spazio dei nomi, ma sono troppo vaghe, possono essere sovrascritte in fase di esecuzione e gli IDE raramente (mai?) Sanno come riempire automaticamente le loro chiavi.

Ci sono soluzioni / soluzioni alternative che usi comunemente? Qualcuno ricorda se i ragazzi di PHP hanno avuto pensieri o decisioni sugli enum?

È stato utile?

Soluzione

A seconda del caso d'uso, normalmente userei qualcosa di semplice come il seguente:

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

$today = DaysOfWeek::Sunday;

Tuttavia, altri casi d'uso potrebbero richiedere una maggiore convalida di costanti e valori. Sulla base dei commenti seguenti sulla riflessione e alcune altre note , ecco un esempio ampliato che potrebbe servire meglio una gamma molto più ampia dei casi:

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

Creando una semplice classe enum che estende BasicEnum, ora hai la possibilità di utilizzare i metodi in questo modo per una semplice convalida dell'input:

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

Come nota a margine, ogni volta che uso la riflessione almeno una volta su una classe statica / const in cui i dati non cambieranno (come in un enum), memorizzo nella cache i risultati di quelli richiami di riflessione, poiché l'utilizzo di nuovi oggetti di riflessione ogni volta avrà un impatto notevole sulle prestazioni (memorizzato in un array assocciativo per più enumerazioni).

Ora che la maggior parte delle persone ha finalmente aggiornato almeno alla versione 5.3 e SplEnum è disponibile, questa è certamente un'opzione praticabile, a patto che tu non lo faccia ' attenzione alla nozione tradizionalmente non intuitiva di avere enum istanze effettive in tutta la tua base di codice. Nell'esempio sopra, BasicEnum e DaysOfWeek non possono essere istanziati affatto, né dovrebbero esserlo.

Altri suggerimenti

Esiste anche un'estensione nativa. Il SplEnum

  

SplEnum offre la possibilità di emulare e creare oggetti di enumerazione   nativamente in PHP.

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

E le costanti di classe?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

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

echo YourClass::SOME_CONSTANT;

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

La risposta più sopra è fantastica. Tuttavia, se lo estendi in due modi diversi, qualunque estensione venga eseguita per prima, una chiamata alle funzioni creerà la cache. Questa cache verrà quindi utilizzata da tutte le chiamate successive, indipendentemente dall'estensione che le chiamate vengono avviate da ...

Per risolvere questo problema, sostituisci la variabile e la prima funzione 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 invece di class :

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

var $today = DaysOfWeek::Sunday;

Ho usato le classi con costanti:

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

print Enum::NAME;

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

final class TestEnum
{

    private static 

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Ho commentato alcune delle altre risposte qui, quindi ho pensato che avrei peso anche io. Alla fine della giornata, poiché PHP non supporta le enumerazioni tipizzate, puoi procedere in due modi: hackerare le enumerazioni tipizzate o convivere con il fatto che sono estremamente difficili da hackerare in modo efficace.

Preferisco convivere con il fatto, e invece uso il metodo const che altre risposte qui hanno usato in un modo o nell'altro:

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 esempio di enumerazione:

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;

}

L'uso di Enum come classe di base da cui si estendono tutte le altre enumerazioni consente metodi di supporto, come toArray , isValid e così via . Per me, gli elenchi digitati ( e la gestione delle loro istanze ) finiscono per essere troppo disordinati.


ipotetico

Se , esisteva un metodo magico __getStatic ( e preferibilmente un metodo magico __equals troppo ) questo potrebbe essere mitigato con una sorta di modello multitono.

( Quanto segue è ipotetico; non funzionerà , sebbene forse un giorno funzionerà )

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

Bene, per un semplice java come enum in php, io 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];
    }
}

E per chiamarlo:

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

Ma sono un principiante di PHP, alle prese con la sintassi, quindi questo potrebbe non essere il modo migliore. Ho sperimentato alcuni con Costanti di classe, usando Reflection per ottenere il nome costante dal suo valore, potrebbe essere più pulito.

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

abstract class TypedEnum
{
    private static 

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

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

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

Esempio di utilizzo:

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

Nota che tutte le istanze della stessa voce enum sono uguali:

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

Puoi anche usarlo all'interno di un'istruzione switch:

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

Puoi anche creare una voce enum per nome o valore:

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

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

<*>instancedValues; private

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

<*>value; private

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Quattro anni dopo me ne sono imbattuto di nuovo. Il mio approccio attuale è questo in quanto consente il completamento del codice nell'IDE e la sicurezza del tipo:

Classe base:

<*>

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

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

Esempio Enum:

<*>

Esempio di utilizzo:

<*>

Nota che tutte le istanze della stessa voce enum sono uguali:

<*>

Puoi anche usarlo all'interno di un'istruzione switch:

<*>

Puoi anche creare una voce enum per nome o valore:

<*>

Oppure puoi semplicemente ottenere il nome (cioè il nome della funzione) da una voce enum esistente:

<*>

Se hai bisogno di usare enum univoci a livello globale (cioè anche quando si confrontano elementi tra Enum diversi) e sono facili da usare, sentiti libero di usare il seguente codice. Ho anche aggiunto alcuni metodi che trovo utili. Troverai esempi nei commenti all'inizio del codice.

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

Se hai bisogno di usare enum univoci a livello globale (cioè anche quando si confrontano elementi tra Enum diversi) e sono facili da usare, sentiti libero di usare il seguente codice. Ho anche aggiunto alcuni metodi che trovo utili. Troverai esempi nei commenti all'inizio del codice.

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

Se hai bisogno di usare enum univoci a livello globale (cioè anche quando si confrontano elementi tra Enum diversi) e sono facili da usare, sentiti libero di usare il seguente codice. Ho anche aggiunto alcuni metodi che trovo utili. Troverai esempi nei commenti all'inizio del codice.

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

Mi piacciono anche gli enum di Java e per questo motivo scrivo i miei enum in questo modo, penso che questo sia il comportamento più simile come negli enum di Java, ovviamente, se qualcuno vuole usare più metodi da Java dovrebbe scriverlo qui o in classe astratta ma l'idea di base è incorporata nel codice seguente


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

Ho trovato questa libreria su github e penso che offra un'alternativa molto decente alle risposte qui.

Implementazione di PHP Enum ispirata a SplEnum

  • Puoi digitare-hint: function setAction (Action $ action) {
  • Puoi arricchire l'enum con metodi (ad es. format , parse , ...)
  • Puoi estendere l'enum per aggiungere nuovi valori (rendi il tuo enum final per impedirlo)
  • Puoi ottenere un elenco di tutti i possibili valori (vedi sotto)

Dichiarazione

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

valori enum di suggerimento tipo:

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

La soluzione più comune che ho visto per enum in PHP è stata quella di creare una classe enum generica e quindi estenderla. Puoi dare un'occhiata a questo .

AGGIORNAMENTO: In alternativa, ho trovato questo da phpclasses.org.

Ecco una libreria github per la gestione di enumerazioni di tipo sicuro in php:

Questa libreria gestisce la generazione di classi, la memorizzazione nella cache delle classi e implementa il modello di progettazione di enumerazione sicura dei tipi, con diversi metodi di supporto per gestire gli enum, come il recupero di un ordinale per l'ordinamento degli enum o il recupero di un valore binario, per combinazioni di enum.

Il codice generato utilizza un semplice vecchio file modello php, che è anche configurabile, quindi puoi fornire il tuo modello.

È un test completo coperto da phpunit.

php-enums su github (sentiti libero di fare fork)

Utilizzo: (@vedere use.php o test unitari per maggiori dettagli)

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

Output:

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

Potrebbe essere semplice come

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

in futuro.

PHP RFC: tipi enumerati

Ho scelto di utilizzare l'approccio seguente in quanto mi dà la possibilità di avere la sicurezza del tipo per i parametri delle funzioni, il completamento automatico in NetBeans e buone prestazioni. L'unica cosa che non mi piace troppo è che devi chiamare [nome classe estesa] :: enumerate (); dopo aver definito la classe.

abstract class Enum {

    private 

Ho scelto di utilizzare l'approccio seguente in quanto mi dà la possibilità di avere la sicurezza del tipo per i parametri delle funzioni, il completamento automatico in NetBeans e buone prestazioni. L'unica cosa che non mi piace troppo è che devi chiamare [nome classe estesa] :: enumerate (); dopo aver definito la classe.

<*>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 definizione della mia classe Enum di seguito è fortemente tipizzata e molto naturale da usare e definire.

Definizione:

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

Passa su Enum

$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

Passa Enum come parametro (fortemente tipizzato)

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

echo "I have an $myFruit\n";

>> I have an APPLE

Ottieni Enum per numero intero

$myFruit = Fruit::getByValue(2);

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

>> Now I have an ORANGE

Ottieni Enum per nome

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

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

>> But I definitely prefer an APPLE

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

}

Aggiunta

Puoi ovviamente aggiungere anche commenti per gli 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();

Mi rendo conto che questo è un thread molto molto molto vecchio, ma ci ho pensato e volevo sapere cosa pensavano le persone.

Note: stavo giocando con questo e mi sono reso conto che se avessi appena modificato la funzione __call () , potresti avvicinarti ancora di più ai veri enum . La funzione __call () gestisce tutte le chiamate di funzioni sconosciute. Supponiamo quindi che tu voglia creare tre enum RED_LIGHT, YELLOW_LIGHT e GREEN_LIGHT. Puoi farlo ora semplicemente facendo quanto segue:

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

Una volta definito, tutto ciò che devi fare è richiamarli per ottenere i valori:

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

e dovresti ottenere 0, 1 e 2. Buon divertimento! Anche questo è ora su GitHub.

Aggiornamento: l'ho fatto in modo che entrambe le funzioni __get () e __set () siano ora utilizzate. Questi ti consentono di non dover chiamare una funzione a meno che tu non voglia. Invece, ora puoi semplicemente dire:

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

Sia per la creazione che per l'acquisizione dei valori. Poiché le variabili non sono state definite inizialmente, viene chiamata la funzione __get () (poiché non è stato specificato un valore) che vede che la voce nell'array non è stata creata. Quindi crea la voce, le assegna l'ultimo valore dato più uno (+1), incrementa l'ultima variabile del valore e restituisce VERO. Se si imposta il valore:

$c->RED_LIGHT = 85;

Quindi viene chiamata la funzione __set () e l'ultimo valore viene quindi impostato sul nuovo valore più uno (+1). Quindi ora abbiamo un buon modo per fare enumerazioni e possono essere create al volo.

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

?>

So che questo è un vecchio thread, tuttavia nessuna delle soluzioni alternative che ho visto sembrava davvero un enum, dal momento che quasi tutte le soluzioni alternative richiedono di assegnare manualmente i valori agli elementi enum o di passare una matrice di enum tasti per una funzione. Quindi ho creato la mia soluzione per questo.

Per creare una classe enum usando la mia soluzione si può semplicemente estendere questa classe Enum di seguito, creare un gruppo di variabili statiche (non è necessario inizializzarle) ed effettuare una chiamata a yourEnumClass :: init () appena sotto la definizione di la tua classe enum.

modifica: funziona solo in php > = 5.3, ma può probabilmente essere modificato per funzionare anche nelle versioni precedenti     

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

Ora puoi usare la classe SplEnum per crearla nativamente. Come da documentazione ufficiale.

  

SplEnum offre la possibilità di emulare e creare oggetti di enumerazione   nativamente in 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;
}
?>

Nota, è un'estensione che deve essere installata, ma non disponibile per impostazione predefinita. Che rientra nei Tipi speciali descritti nello stesso sito web php. L'esempio sopra è tratto dal sito PHP.

La risposta accettata è la strada da percorrere ed è in realtà ciò che sto facendo per semplicità. Vengono offerti la maggior parte dei vantaggi dell'enumerazione (leggibile, veloce, ecc.). Manca tuttavia un concetto: digitare la sicurezza. Nella maggior parte delle lingue, le enumerazioni vengono utilizzate anche per limitare i valori consentiti. Di seguito è riportato un esempio di come la sicurezza dei tipi può essere ottenuta anche utilizzando costruttori privati, metodi di istanza statica e verifica del tipo:

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

Potremmo anche andare oltre: l'uso di costanti nella classe DaysOfWeek potrebbe portare a errori di utilizzo: ad es. si potrebbe erroneamente usarlo in questo modo:

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

che è sbagliato (chiama la costante intera). Possiamo impedirlo utilizzando variabili statiche private anziché costanti:

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

}

Naturalmente, non è possibile accedere a costanti intere (questo era in realtà lo scopo). Il metodo intVal consente di convertire un oggetto DaysOfWeek nella sua rappresentazione intera.

Si noti che potremmo anche andare oltre implementando un meccanismo di memorizzazione nella cache nei metodi di istanza per risparmiare memoria nel caso in cui le enumerazioni siano ampiamente utilizzate ...

Spero che questo possa aiutare

Alcune buone soluzioni qui!

Ecco la mia versione.

  • È fortemente tipizzato
  • Funziona con il completamento automatico IDE
  • Gli enum sono definiti da un codice e una descrizione, in cui il codice può essere un numero intero, un valore binario, una stringa breve o praticamente qualsiasi altra cosa tu voglia. Il modello potrebbe essere facilmente esteso per supportare altre proprietà.
  • Supporta confronti di valore (==) e riferimento (===) e funziona nelle istruzioni switch.

Penso che il principale svantaggio sia che i membri di enum devono essere dichiarati e istanziati separatamente, a causa delle descrizioni e dell'incapacità di PHP di costruire oggetti al momento della dichiarazione dei membri statici. Immagino che un modo per aggirare questo potrebbe essere invece quello di utilizzare la riflessione con commenti doc analizzati

L'enum astratto appare così:

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

Ecco un esempio concreto:

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

Che può essere usato in questo modo:

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

E produce questo output:

  

1: il mio primo valore

     

array (3) {
       [1] = >
       object (EMyEnum) # 1 (2) {
         [& Quot; il codice ": " AbstractEnum ": private] = >
         int (1)
         [& Quot; Descrizione ": " AbstractEnum ": privato] = >
         string (14) " Il mio primo valore "
       }
       [2] = >
       object (EMyEnum) # 2 (2) {
         [& Quot; il codice ": " AbstractEnum ": private] = >
         int (2)
         [& Quot; Descrizione ": " AbstractEnum ": privato] = >
         string (15) " Il mio secondo valore "
       }
       [3] = >
       object (EMyEnum) # 3 (2) {
         [& Quot; il codice ": " AbstractEnum ": private] = >
         int (3)
         [& Quot; Descrizione ": " AbstractEnum ": privato] = >
         string (14) " Il mio terzo valore "
       }
     }

     

Il mio secondo valore

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

Non usare la riflessione. Rende estremamente difficile ragionare sul tuo codice e rintracciare dove viene utilizzato qualcosa e tende a rompere gli strumenti di analisi statica (ad esempio cosa è incorporato nel tuo IDE).

Uno degli aspetti mancanti in alcune delle altre risposte qui è un modo per usare gli enum con il suggerimento sul tipo.

Se definisci il tuo enum come un insieme di costanti in una classe astratta, ad esempio

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

quindi non è possibile digitare un suggerimento in un parametro di funzione - per uno, perché non è istantaneo, ma anche perché il tipo di ShirtSize :: SMALL è int , non ShirtSize .

Ecco perché gli enum nativi in ??PHP sarebbero molto meglio di qualsiasi cosa possiamo inventare. Tuttavia, possiamo approssimare un enum mantenendo una proprietà privata che rappresenta il valore dell'enum e quindi limitando l'inizializzazione di questa proprietà alle nostre costanti predefinite. Per evitare che l'enum venga istanziato arbitrariamente (senza il sovraccarico del controllo del tipo di una whitelist), rendiamo privato il costruttore.

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

Quindi possiamo usare ShirtSize in questo modo:

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

Uno degli aspetti mancanti in alcune delle altre risposte qui è un modo per usare gli enum con il suggerimento sul tipo.

Se definisci il tuo enum come un insieme di costanti in una classe astratta, ad esempio

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

quindi non è possibile digitare un suggerimento in un parametro di funzione - per uno, perché non è istantaneo, ma anche perché il tipo di ShirtSize :: SMALL è int , non ShirtSize .

Ecco perché gli enum nativi in ??PHP sarebbero molto meglio di qualsiasi cosa possiamo inventare. Tuttavia, possiamo approssimare un enum mantenendo una proprietà privata che rappresenta il valore dell'enum e quindi limitando l'inizializzazione di questa proprietà alle nostre costanti predefinite. Per evitare che l'enum venga istanziato arbitrariamente (senza il sovraccarico del controllo del tipo di una whitelist), rendiamo privato il costruttore.

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

Quindi possiamo usare ShirtSize in questo modo:

<*>

In questo modo, la più grande differenza dal punto di vista dell'utente è che devi puntare su un () sul nome della costante.

Un aspetto negativo è che === (che confronta l'uguaglianza degli oggetti) restituirà false quando == restituisce true. Per questo motivo, è meglio fornire un metodo uguale a , in modo che gli utenti non debbano ricordare di usare == e non === per confrontare due valori enum.

EDIT: un paio di risposte esistenti sono molto simili, in particolare: 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";

In questo modo, la più grande differenza dal punto di vista dell'utente è che devi puntare su un () sul nome della costante.

Un aspetto negativo è che === (che confronta l'uguaglianza degli oggetti) restituirà false quando == restituisce true. Per questo motivo, è meglio fornire un metodo uguale a , in modo che gli utenti non debbano ricordare di usare == e non === per confrontare due valori enum.

EDIT: un paio di risposte esistenti sono molto simili, in particolare: https://stackoverflow.com/a/25526473/2407870 .

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

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

Calpestando la risposta di @Brian Cline, ho pensato di poter dare i miei 5 centesimi

<*>constCacheArray[$calledClass]; } }

Questa è la mia opinione su " dinamico " enum ... così che posso chiamarlo con variabili, es. da un modulo.

guarda la versione aggiornata sotto questo blocco di codice ...

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

AGGIORNAMENTO: modo migliore per farlo ...

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;

}

Chiama con

EnumCategory::${$category};

Ieri ho scritto questa classe sul mio blog . Penso che sia forse facile da usare negli script 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;
    }
}

Utilizzo:

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

La soluzione evidenziata funziona bene. Pulito e liscio.

Tuttavia, se si desidera enumerazioni fortemente tipizzate, è possibile utilizzare questo:

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

Con una classe Enum simile 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;
    }
}

In questo modo, i valori enum sono fortemente tipizzati e

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

Ho creato una libreria basata sulla risposta di Brian Cline, che si chiama greg0ire / enum Buon divertimento!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top