Question

Je sais que PHP n'a pas d'énumérations natives. Mais je m'y suis habitué depuis le monde Java. J'aimerais utiliser des enums comme moyen de donner des valeurs prédéfinies que les fonctionnalités de complétion automatique des IDE pourraient comprendre.

Les constantes font l'affaire, mais il existe un problème de collision d'espace de noms et (ou en fait parce que ), elles sont globales. Les tableaux n'ont pas le problème de l'espace de noms, mais ils sont trop vagues, ils peuvent être écrasés à l'exécution et les IDE savent rarement (jamais?) Comment remplir automatiquement leurs clés.

Y a-t-il des solutions / solutions de contournement que vous utilisez couramment? Est-ce que quelqu'un se souvient si les gars de PHP ont eu des idées ou des décisions concernant les énumérations?

Était-ce utile?

La solution

En fonction du cas d'utilisation, j'utiliserais normalement quelque chose simple comme suit:

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

$today = DaysOfWeek::Sunday;

Cependant, d'autres cas d'utilisation peuvent nécessiter davantage de validation des constantes et des valeurs. En vous basant sur les commentaires ci-dessous sur la réflexion et sur quelques notes , voici un exemple plus complet qui pourrait mieux servir une gamme beaucoup plus large. des cas:

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

En créant une classe enum simple qui étend BasicEnum, vous avez désormais la possibilité d'utiliser des méthodes pour la validation des entrées simples:

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

En remarque, chaque fois que j'utilise la réflexion au moins une fois sur une classe statique / constante où les données ne changent pas (comme dans un enum), je mets en cache les résultats de ces dernières. appels de réflexion, car l’utilisation répétée d’objets de réflexion chaque fois aura finalement un impact notable sur les performances (stockée dans un tableau associative pendant plusieurs énumérations).

Maintenant que la plupart des gens ont finalement mis à niveau vers la version 5.3, et que SplEnum est disponible, il s'agit certainement d'une option viable - tant que vous ne l'utilisez pas. Faites attention à la notion traditionnellement peu intuitive d’avoir des instanciations enum dans votre base de code. Dans l'exemple ci-dessus, BasicEnum et DaysOfWeek ne peuvent pas être instanciés, pas plus qu'ils ne devraient l'être.

Autres conseils

Il existe également une extension native. Le SplEnum

  

SplEnum permet d'émuler et de créer des objets d'énumération.   nativement en PHP.

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

Qu'en est-il des constantes de 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 réponse ci-dessus est fantastique. Cependant, si vous le étendez de deux manières différentes, quelle que soit l'extension effectuée, le premier appel des fonctions créera le cache. Ce cache sera ensuite utilisé par tous les appels suivants, quelle que soit l’extension où les appels sont initiés par ...

Pour résoudre ce problème, remplacez la variable et la première fonction par:

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

J'utilise interface au lieu de classe :

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

var $today = DaysOfWeek::Sunday;

J'ai utilisé des classes avec des constantes:

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

print Enum::NAME;

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

final class TestEnum
{

    private static 

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

J'ai commenté certaines des autres réponses ici, alors je me suis dit que j'allais intervenir aussi. En fin de compte, étant donné que PHP ne prend pas en charge les énumérations dactylographiées, vous pouvez choisir l’une des deux méthodes suivantes: hackez les énumérations tapées ou vivez le fait qu’elles sont extrêmement difficiles à pirater efficacement.

Je préfère vivre avec le fait et utiliser plutôt la méthode const que d'autres réponses ici ont utilisée d'une manière ou d'une autre:

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 exemple d'énumération:

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'utilisation de Enum en tant que classe de base à partir de laquelle toutes les autres énumérations sont étendues autorise les méthodes d'assistance, telles que toArray , isValid , etc. . Pour moi, les énumérations saisies ( et la gestion de leurs instances ) finissent par être trop compliquées.

Hypothétique

Si , il existait une méthode magique __ getStatic ( et de préférence une méthode magique __ est égal à aussi ) cela pourrait être atténué par une sorte de motif multiton.

( Ce qui suit est hypothétique; cela ne fonctionnera pas , mais peut-être qu'un jour )

.

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

Eh bien, pour un java simple comme énum en php, j’utilise:

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

Et pour l'appeler:

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

Mais je suis un débutant en PHP, je ne parviens pas à utiliser la syntaxe, alors ce n’est peut-être pas la meilleure solution. J'en ai expérimenté certaines avec les constantes de classe, en utilisant Reflection pour obtenir le nom de la constante à partir de sa valeur, cela pourrait être plus simple.

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

abstract class TypedEnum
{
    private static 

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

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

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

Exemple d'utilisation:

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

Notez que toutes les instances de la même entrée enum sont identiques:

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

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

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

Vous pouvez également créer une entrée enum par nom ou valeur:

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

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

<*>instancedValues; private

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

<*>value; private

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Quatre ans plus tard, je suis tombé de nouveau sur cette affaire Mon approche actuelle est la suivante: elle permet de compléter le code dans l’EDI ainsi que de définir la sécurité:

Classe de base:

<*>

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

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

Exemple Enum:

<*>

Exemple d'utilisation:

<*>

Notez que toutes les instances de la même entrée enum sont identiques:

<*>

Vous pouvez également l'utiliser à l'intérieur d'une instruction switch:

<*>

Vous pouvez également créer une entrée enum par nom ou valeur:

<*>

Ou vous pouvez simplement obtenir le nom (c'est-à-dire le nom de la fonction) à partir d'une entrée enum existante:

<*>

Si vous devez utiliser des énumérations globalement uniques (c'est-à-dire même lorsque vous comparez des éléments entre différentes énumérations) et faciles à utiliser, n'hésitez pas à utiliser le code suivant. J'ai également ajouté des méthodes que je trouve utiles. Vous trouverez des exemples dans les commentaires tout en haut du code.

<?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 vous devez utiliser des énumérations globalement uniques (c'est-à-dire même lorsque vous comparez des éléments entre différentes énumérations) et faciles à utiliser, n'hésitez pas à utiliser le code suivant. J'ai également ajouté des méthodes que je trouve utiles. Vous trouverez des exemples dans les commentaires tout en haut du code.

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

Si vous devez utiliser des énumérations globalement uniques (c'est-à-dire même lorsque vous comparez des éléments entre différentes énumérations) et faciles à utiliser, n'hésitez pas à utiliser le code suivant. J'ai également ajouté des méthodes que je trouve utiles. Vous trouverez des exemples dans les commentaires tout en haut du code.

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

J'aime aussi les enums de java et c’est pour cette raison que j’écris mes énums de cette façon. Je pense que c’est le behawior le plus similaire, comme dans les enums de Java, bien sûr, si certains veulent utiliser plus de méthodes de Java devraient l’écrire ici , ou en classe abstraite mais l'idée de base est incorporée dans le code ci-dessous


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

J'ai trouvé cette bibliothèque sur github et je pense que cela fournit une très bonne alternative aux réponses. ici.

Implémentation PHP Enum inspirée de SplEnum

  • Vous pouvez taper un indice: function setAction (Action $ action) {
  • Vous pouvez enrichir l'énumération avec des méthodes (par exemple, format , analyse ,…)
  • Vous pouvez étendre l'énumération pour ajouter de nouvelles valeurs (définissez votre enum final pour l'empêcher)
  • Vous pouvez obtenir une liste de toutes les valeurs possibles (voir ci-dessous)

Déclaration

<?php
use MyCLabs\Enum\Enum;

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

Utilisation

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

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

valeurs d'énumération d'indice de type:

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

La solution la plus courante que j'ai vue enum en PHP consiste à créer une classe enum générique, puis à l'étendre. Vous pouvez consulter this .

UPDATE: J'ai également trouvé this . de phpclasses.org.

Voici une bibliothèque github pour gérer les énumérations de type sécuritaire en php:

Cette bibliothèque gère la génération de classes, la mise en cache de classes et implémente le modèle de conception Type Safe Enumeration, avec plusieurs méthodes d'assistance pour traiter les énumérations, telles que la récupération d'un ordinal pour le tri des énumérations ou la récupération d'une valeur binaire, pour les combinaisons d'énums.

Le code généré utilise un vieux fichier de modèle php brut, qui est également configurable, vous pouvez donc fournir votre propre modèle.

C’est un test complet recouvert de phpunit.

php-enums sur github (n'hésitez pas à fourcher)

Utilisation: (@voir usage.php, ou tests unitaires pour plus de détails)

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

Sortie:

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

Cela pourrait être aussi simple que

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

à l'avenir.

RFC PHP: Types énumérés

J’ai commencé à utiliser l’approche ci-dessous car elle me permet d’avoir la sécurité de type pour les paramètres de fonction, la complétion automatique dans NetBeans et de bonnes performances. La seule chose que je n'aime pas trop, c'est que vous devez appeler [nom de la classe étendue] :: enumerate (); après avoir défini la classe.

abstract class Enum {

    private 

J’ai commencé à utiliser l’approche ci-dessous car elle me permet d’avoir la sécurité de type pour les paramètres de fonction, la complétion automatique dans NetBeans et de bonnes performances. La seule chose que je n'aime pas trop, c'est que vous devez appeler [nom de la classe étendue] :: enumerate (); après avoir défini 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 définition de la classe Mon Enum ci-dessous est fortement typée et très naturelle à utiliser et à définir.

Définition:

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

Basculez sur 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

Transférer Enum en paramètre (fortement typé)

/** 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 en tant que chaîne

echo "I have an $myFruit\n";

>> I have an APPLE

Obtenir l'énumération par un entier

$myFruit = Fruit::getByValue(2);

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

>> Now I have an ORANGE

Obtenez l'énumération par nom

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

}

Ajout

Vous pouvez bien sûr aussi ajouter des commentaires pour les 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();

Je réalise que c’est un très vieux fil, mais j’avais une pensée à ce sujet et je voulais savoir ce que les gens pensaient.

Notes: Je me suis amusé avec cela et je me suis rendu compte que si je venais de modifier la fonction __ call () , vous pourriez vous rapprocher encore plus des véritables enums . La fonction __ call () gère tous les appels de fonction inconnus. Supposons donc que vous souhaitiez créer trois enums RED_LIGHT, YELLOW_LIGHT et GREEN_LIGHT. Vous pouvez le faire maintenant en procédant simplement comme suit:

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

Une fois défini, tout ce que vous avez à faire est de les appeler à nouveau pour obtenir les valeurs:

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

et vous devriez obtenir 0, 1 et 2. Amusez-vous! C’est également le cas sur GitHub.

Mise à jour: je l'ai fait pour que les fonctions __ get () et __ set () soient maintenant utilisées. Celles-ci vous permettent de ne pas avoir à appeler une fonction sauf si vous le souhaitez. Au lieu de cela, vous pouvez maintenant dire:

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

Pour la création et l'obtention des valeurs. Les variables n'ayant pas encore été définies, la fonction __ get () est appelée (car aucune valeur n'a été spécifiée), ce qui permet de voir que l'entrée dans le tableau n'a pas été effectuée. Ainsi, il crée l'entrée, lui attribue la dernière valeur donnée plus un (+1), incrémente la dernière variable de valeur et renvoie la valeur VRAI. Si vous définissez la valeur:

$c->RED_LIGHT = 85;

La fonction __ set () est ensuite appelée et la dernière valeur est définie sur la nouvelle valeur plus un (+1). Nous avons donc maintenant un bon moyen de faire des énumérations qui peuvent être créées à la volée.

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

?>

Je sais que c'est un ancien fil de discussion, mais aucune des solutions de contournement que j'ai vues ne ressemble vraiment à un enum, car presque toutes les solutions de contournement nécessitent d'octroyer manuellement des valeurs aux éléments enum ou de passer un tableau d'enum. touches d'une fonction. J'ai donc créé ma propre solution pour cela.

Pour créer une classe enum en utilisant ma solution, il suffit d’étendre cette classe Enum ci-dessous, de créer un groupe de variables statiques (inutile de les initialiser) et d’appeler votreEnumClass :: init () juste en dessous de la définition de votre classe enum.

modifier: cela ne fonctionne que dans php > = 5.3, mais il peut probablement être modifié pour fonctionner également dans les anciennes versions     

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

Vous pouvez maintenant utiliser la classe SplEnum pour le construire de manière native. Selon la documentation officielle.

  

SplEnum permet d'émuler et de créer des objets d'énumération.   nativement 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;
}
?>

Veuillez noter que c'est une extension qui doit être installée, mais non disponible par défaut. Ce qui relève de Types spéciaux décrits dans le site Web php lui-même. L'exemple ci-dessus est tiré du site PHP.

La réponse acceptée est la voie à suivre et c’est ce que je fais pour plus de simplicité. La plupart des avantages de l'énumération sont offerts (lisibles, rapides, etc.). Il manque cependant un concept: le type sécurité. Dans la plupart des langues, les énumérations sont également utilisées pour limiter les valeurs autorisées. Vous trouverez ci-dessous un exemple de la manière dont la sécurité de type peut également être obtenue à l'aide de constructeurs privés, de méthodes d'instanciation statique et de vérification de type:

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

Nous pourrions même aller plus loin: l’utilisation de constantes dans la classe DaysOfWeek pourrait conduire à des utilisations abusives: par ex. on pourrait l'utiliser à tort de cette façon:

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

qui est faux (appelle une constante entière). Nous pouvons empêcher cela en utilisant des variables statiques privées à la place 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;
  }

}

Bien sûr, il n’est pas possible d’accéder aux constantes de nombres entiers (c’était en fait le but). La méthode intVal permet de convertir un objet DaysOfWeek en une représentation entière.

Notez que nous pourrions même aller plus loin en implémentant un mécanisme de mise en cache dans les méthodes d'instanciation afin d'économiser de la mémoire dans le cas où les énumérations sont largement utilisées ...

J'espère que cela vous aidera

Quelques bonnes solutions ici!

Voici ma version.

  • Il est fortement typé
  • Cela fonctionne avec la complétion automatique de l'IDE
  • Les énumérations sont définies par un code et une description, le code pouvant être un entier, une valeur binaire, une chaîne courte ou tout ce que vous voulez. Le motif pourrait facilement être étendu pour supporter d’autres propriétés.
  • Il prend en charge les comparaisons de valeur (==) et de référence (===) et fonctionne dans les instructions switch.

Je pense que le principal inconvénient est que les membres enum doivent être déclarés et instanciés séparément, en raison des descriptions et de l'incapacité de PHP à construire des objets au moment de la déclaration des membres statiques. J'imagine que cela pourrait être d'utiliser la réflexion avec des commentaires doc analysés.

L'énumération abstraite ressemble à ceci:

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

Voici un exemple concret d'énumération:

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

Ce qui peut être utilisé comme ceci:

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

Et produit cette sortie:

  

1: Ma première valeur

     

array (3) {
       [1] = >
       objet (EMyEnum) # 1 (2) {
         [" code ":" AbstractEnum ": private] = >
         int (1)
         ["description": "AbstractEnum": private] = >
         string (14) "Ma première valeur"

       }
       [2] = >
       object (EMyEnum) # 2 (2) {
         [" code ":" AbstractEnum ": private] = >
         int (2)
         ["description": "AbstractEnum": private] = >
         string (15) "Ma deuxième valeur"

       }
       [3] = >
       objet (EMyEnum) # 3 (2) {
         [" code ":" AbstractEnum ": private] = >
         int (3)
         ["description": "AbstractEnum": private] = >
         string (14) "Ma troisième valeur"

       }
     }

     

Ma deuxième valeur

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

N'utilisez pas de réflexion. Il est extrêmement difficile de raisonner sur votre code et de localiser l’utilisation de quelque chose, et a tendance à casser les outils d’analyse statique (par exemple, ce qui est intégré à votre IDE).

Un des aspects qui manque dans certaines des autres réponses ici est la possibilité d'utiliser des énumérations avec des indications de type.

Si vous définissez votre énumération comme un ensemble de constantes dans une classe abstraite, par exemple.

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

alors vous ne pouvez pas taper le conseil dans un paramètre de fonction - par exemple, parce que ce n'est pas instantiable, mais aussi parce que le type de ShirtSize :: SMALL est int , pas ShirtSize .

C'est pourquoi les énumérations natives en PHP seraient tellement meilleures que tout ce que nous pouvons trouver. Cependant, nous pouvons approximer une énumération en conservant une propriété privée qui représente la valeur de cette énumération, puis en limitant l'initialisation de cette propriété à nos constantes prédéfinies. Pour empêcher l'instanciation arbitraire de l'énum (sans la surcharge de la vérification du type dans une liste blanche), nous rendons le constructeur privé.

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

Ensuite, nous pouvons utiliser ShirtSize comme ceci:

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

Un des aspects qui manque dans certaines des autres réponses ici est la possibilité d'utiliser des énumérations avec des indications de type.

Si vous définissez votre énumération comme un ensemble de constantes dans une classe abstraite, par exemple.

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

alors vous ne pouvez pas taper le conseil dans un paramètre de fonction - par exemple, parce que ce n'est pas instantiable, mais aussi parce que le type de ShirtSize :: SMALL est int , pas ShirtSize .

C'est pourquoi les énumérations natives en PHP seraient tellement meilleures que tout ce que nous pouvons trouver. Cependant, nous pouvons approximer une énumération en conservant une propriété privée qui représente la valeur de cette énumération, puis en limitant l'initialisation de cette propriété à nos constantes prédéfinies. Pour empêcher l'instanciation arbitraire de l'énum (sans la surcharge de la vérification du type dans une liste blanche), nous rendons le constructeur privé.

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

Ensuite, nous pouvons utiliser ShirtSize comme ceci:

<*>

De cette façon, la plus grande différence du point de vue de l'utilisateur est que vous devez vous baser sur un () sur le nom de la constante.

Un inconvénient cependant est que === (qui compare l'égalité d'objet) renverra false lorsque == renvoie true. Pour cette raison, il est préférable de fournir une méthode égale à , afin que les utilisateurs n'aient pas à se souvenir d'utiliser == et non === comparer deux valeurs enum.

EDIT: Quelques réponses existantes sont très similaires, notamment: 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 cette façon, la plus grande différence du point de vue de l'utilisateur est que vous devez vous baser sur un () sur le nom de la constante.

Un inconvénient cependant est que === (qui compare l'égalité d'objet) renverra false lorsque == renvoie true. Pour cette raison, il est préférable de fournir une méthode égale à , afin que les utilisateurs n'aient pas à se souvenir d'utiliser == et non === comparer deux valeurs enum.

EDIT: Quelques réponses existantes sont très similaires, notamment: https://stackoverflow.com/a/25526473/2407870 .

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

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

Marchant sur la réponse de @Brian Cline, je pensais pouvoir donner mes 5 centimes

<*>constCacheArray[$calledClass]; } }

C’est mon point de vue sur "dynamique". enum ... afin que je puisse l'appeler avec des variables, ex. à partir d'un formulaire.

regardez la version mise à jour sous ce codeblock ...

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

MISE À JOUR: Une meilleure façon de le faire ...

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;

}

Appeler avec

EnumCategory::${$category};

Hier, j'ai écrit ce cours sur mon blog . . Je pense que c'est peut-être facile à utiliser dans les 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;
    }
}

Utilisation:

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

La solution indiquée fonctionne bien. Propre et lisse.

Cependant, si vous voulez des énumérations fortement typées, vous pouvez utiliser ceci:

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

Avec une classe Enum ressemblant à:

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 cette façon, les valeurs enum sont fortement typées et

TestEnum :: $ TEST1 === TestEnum :: parse ('TEST1') // instruction vraie

J'ai créé une bibliothèque basée sur la réponse de Brian Cline, elle s'appelle greg0ire / enum . Profitez!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top