1317 Stimmen

Aufzählungen in PHP

Ich weiß, dass PHP noch keine nativen Enumerationen hat. Aber ich habe mich an sie aus der Java-Welt gewöhnt. Ich würde Enums gerne als eine Möglichkeit verwenden, vordefinierte Werte anzugeben, die die Autovervollständigungsfunktionen von IDEs verstehen könnten.

Konstanten tun den Trick, aber es gibt das Problem der Namespace-Kollision und (oder eigentlich denn ) sie sind global. Arrays haben das Namespace-Problem nicht, aber sie sind zu vage, sie können zur Laufzeit überschrieben werden und IDEs wissen selten, wie sie ihre Schlüssel ohne zusätzliche statische Analyse-Annotationen oder Attribute automatisch ausfüllen können.

Gibt es Lösungen/Workarounds, die Sie häufig verwenden? Erinnert sich jemand daran, ob die PHP-Leute irgendwelche Gedanken oder Entscheidungen zu Aufzählungen getroffen haben?

0 Stimmen

1 Stimmen

Ich habe eine Umgehungsfunktion erstellt, die Konstanten als bitweise oder nicht aufzählt. Ich habe nicht bemerkt, dass Sie das vorher gefragt haben, aber ich habe hier eine bessere Lösung als Klassenvariablen: stackoverflow.com/questions/3836385/

0 Stimmen

41voto

Neil Townsend Punkte 5924

Die oberste Antwort oben ist fantastisch. Allerdings, wenn Sie extend dann wird der Cache auf zwei verschiedene Arten erstellt, je nachdem, welche Erweiterung zuerst zu einem Aufruf der Funktionen führt. Dieser Cache wird dann von allen nachfolgenden Aufrufen verwendet, unabhängig davon, durch welche Erweiterung die Aufrufe initiiert werden ...

Um dies zu lösen, ersetzen Sie die Variable und die erste Funktion durch:

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

32voto

Dan Lugg Punkte 19356

Ich habe einige der anderen Antworten hier kommentiert, also dachte ich, ich würde mich auch einbringen. Da PHP keine typisierten Aufzählungen unterstützt, gibt es zwei Möglichkeiten: Entweder man hackt typisierte Aufzählungen, oder man lebt mit der Tatsache, dass es extrem schwierig ist, sie effektiv zu hacken.

Ich ziehe es vor, mit dieser Tatsache zu leben, und verwende stattdessen die const Methode, die andere Antworten hier auf die eine oder andere Weise verwendet haben:

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

}

Ein Beispiel für eine Aufzählung:

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;

}

Verwendung von Enum als Basisklasse, von der alle anderen Aufzählungen abgeleitet werden, ermöglicht Hilfsmethoden, wie z. B. toArray , isValid , und so weiter. Für mich sind typisierte Aufzählungen ( und Verwaltung ihrer Instanzen ) werden einfach zu unordentlich.


Hypothetisch

Wenn gab es eine __getStatic magische Methode ( _und vorzugsweise eine __equals auch magische Methode_ ) könnte vieles davon durch eine Art Multiton-Muster abgemildert werden.

( Die folgenden Ausführungen sind hypothetisch; sie wird nicht Arbeit, aber vielleicht wird sie eines Tages )

final class TestEnum
{

    private static $_values = [
        'FOO' => 1,
        'BAR' => 2,
        'QUX' => 3,
    ];
    private static $_instances = [];

    public static function __getStatic($name)
    {
        if (isset(static::$_values[$name]))
        {
            if (empty(static::$_instances[$name]))
            {
                static::$_instances[$name] = new static($name);
            }
            return static::$_instances[$name];
        }
        throw new Exception(sprintf('Invalid enumeration value, "%s"', $name));
    }

    private $_value;

    public function __construct($name)
    {
        $this->_value = static::$_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

26voto

Andi T Punkte 596

Ich benutze interface anstelle von class :

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

var $today = DaysOfWeek::Sunday;

24voto

aelg Punkte 265

Nun, für eine einfache Java wie enum in php, ich verwenden:

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

Und es zu nennen:

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

Aber ich bin ein PHP-Anfänger, kämpfen mit der Syntax, so dass dies vielleicht nicht der beste Weg sein. Ich experimentierte einige mit Class Constants, mit Reflection, um den Namen der Konstante von seinem Wert zu erhalten, könnte ordentlicher sein.

19voto

Buck Fixing Punkte 219

Vier Jahre später bin ich wieder darauf gestoßen. Mein derzeitiger Ansatz ist dies, da es für Code-Vervollständigung in der IDE sowie Typsicherheit ermöglicht:

Basisklasse:

abstract class TypedEnum
{
    private static $_instancedValues;

    private $_value;
    private $_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::$_instancedValues === null)
        {
            self::$_instancedValues = array();
        }

        $className = get_called_class();

        if (!isset(self::$_instancedValues[$className]))
        {
            self::$_instancedValues[$className] = array();
        }

        if (!isset(self::$_instancedValues[$className][$value]))
        {
            $debugTrace = debug_backtrace();
            $lastCaller = array_shift($debugTrace);

            while ($lastCaller['class'] !== $className && count($debugTrace) > 0)
            {
                $lastCaller = array_shift($debugTrace);
            }

            self::$_instancedValues[$className][$value] = new static($value, $lastCaller['function']);
        }

        return self::$_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;
    }
}

Beispiel Enum:

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

Beispiel für die Verwendung:

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

Beachten Sie, dass alle Instanzen desselben Enum-Eintrags gleich sind:

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

Sie können ihn auch innerhalb einer switch-Anweisung verwenden:

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

Sie können auch einen Enum-Eintrag nach Name oder Wert erstellen:

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

Oder Sie können einfach den Namen (d.h. den Funktionsnamen) aus einem vorhandenen Enum-Eintrag übernehmen:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X