Question PHP et énumérations


Je sais que PHP n'a pas d'énumérations natives. Mais je me suis habitué à eux du monde de Java. J'aimerais utiliser les énumérations comme moyen de donner des valeurs prédéfinies que les fonctions de complétion automatique des IDE pourraient comprendre.

Les constantes font l'affaire, mais il y a le problème de collision d'espace de noms et car) ils sont globaux. Les tableaux n'ont pas le problème d'espace de noms, mais ils sont trop vagues, ils peuvent être écrasés à l'exécution et les EDI savent rarement (jamais?) Comment remplir automatiquement leurs clés.

Existe-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 pensées ou des décisions autour d'enums?


980
2017-10-31 18:51


origine


Réponses:


Selon le cas d'utilisation, j'utiliserais normalement quelque chose simple comme le suivant:

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

$today = DaysOfWeek::Sunday;

Cependant, d'autres cas d'utilisation peuvent nécessiter plus de validation des constantes et des valeurs. Basé sur les commentaires ci-dessous sur la réflexion, et quelques autres notes, voici un exemple développé qui pourrait mieux servir une gamme beaucoup plus large de 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 maintenant la possibilité d'utiliser des méthodes pour la simple validation des entrées:

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 / const où les données ne changeront pas (comme dans une énumération), je cache les résultats de ces appels de réflexion, car l'utilisation de nouveaux objets de réflexion aura à chaque fois un impact notable sur les performances (stocké dans un tableau assocciatif pour plusieurs énumérations).

Maintenant que la plupart des gens ont enfin amélioré à au moins 5,3, et SplEnum est disponible, c'est certainement une option viable aussi - tant que cela ne vous dérange pas la notion traditionnellement non intuitive d'avoir enum instanciations dans votre code. Dans l'exemple ci-dessus, BasicEnum et DaysOfWeek ne peut pas être instancié du tout, et ne devrait pas l'être.


1320
2017-10-31 18:59



Il y a aussi une extension native. le SplEnum

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

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


156
2017-10-31 18:57



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

35
2018-02-03 20:14



La meilleure réponse ci-dessus est fantastique. Cependant, si vous extend de deux façons différentes, alors quelle que soit l'extension qui se produit d'abord dans un appel aux fonctions va créer le cache. Ce cache sera ensuite utilisé par tous les appels suivants, peu importe l'extension à laquelle les appels sont lancé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];
}

27
2017-10-31 18:56



J'ai utilisé des classes avec des constantes:

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

print Enum::NAME;

25
2017-11-24 14:51



j'utilise interface au lieu de class:

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

var $today = DaysOfWeek::Sunday;

24
2017-12-23 20:04



Eh bien, pour un simple java comme enum 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 PHP, luttant avec la syntaxe, donc ce n'est peut-être pas la meilleure façon. J'en ai expérimenté avec les constantes de classe, en utilisant Reflection pour obtenir le nom constant de sa valeur, qui pourrait être plus net.


20
2018-06-11 13:17