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

1648voto

Brian Cline Punkte 19634

Je nach Anwendungsfall würde ich normalerweise etwas verwenden einfach wie die folgenden:

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

$today = DaysOfWeek::Sunday;

Andere Anwendungsfälle können jedoch eine stärkere Validierung von Konstanten und Werten erfordern. Ausgehend von den nachstehenden Bemerkungen zur Reflexion und ein paar andere Anmerkungen Hier ist ein erweitertes Beispiel, das für eine viel größere Anzahl von Fällen besser geeignet ist:

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

Durch die Erstellung einer einfachen Enum-Klasse, die BasicEnum erweitert, haben Sie nun die Möglichkeit, Methoden für eine einfache Eingabevalidierung zu verwenden:

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

Nebenbei bemerkt, jedes Mal, wenn ich die Reflexion mindestens einmal verwende bei einer statischen/konstanten Klasse, bei der sich die Daten nicht ändern werden (z. B. in einem Enum), cache ich die Ergebnisse dieser Reflexion Anrufe, da die Verwendung von frischen Reflexion Objekte jedes Mal schließlich eine spürbare Auswirkungen auf die Leistung haben wird (gespeichert in einem assoziativen Array für mehrere Enums).

Jetzt, wo die meisten Menschen schließlich mindestens auf 5.3 aktualisiert wurde, und SplEnum zur Verfügung steht, ist das sicherlich auch eine praktikable Option - solange Sie sich nicht an der traditionell unintuitiven Idee stören, eine tatsächliche enum Instanzen in Ihrer gesamten Codebasis. Im obigen Beispiel, BasicEnum y DaysOfWeek können überhaupt nicht instanziiert werden, und das sollten sie auch nicht.

189voto

markus Punkte 39397

Es gibt auch eine native Erweiterung. Die SplEnum

SplEnum bietet die Möglichkeit, Aufzählungsobjekte zu emulieren und zu erstellen nativ in PHP zu emulieren und zu erstellen.

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

Achtung!

https://www.php.net/manual/en/spl-types.installation.php

Die PECL-Erweiterung ist nicht im Lieferumfang von PHP enthalten.

Eine DLL für diese PECL-Erweiterung ist derzeit nicht verfügbar.

161voto

yivi Punkte 34209

Ab PHP 8.1 können Sie mit einheimische Aufzählungen .

Die grundlegende Syntax sieht wie folgt aus:

enum TransportMode {
  case Bicycle;
  case Car;
  case Ship;
  case Plane;
  case Feet;
}

function travelCost(TransportMode $mode, int $distance): int
{ /* implementation */ } 

$mode = TransportMode::Boat;

$bikeCost = travelCost(TransportMode::Bicycle, 90);
$boatCost = travelCost($mode, 90);

// this one would fail: (Enums are singletons, not scalars)
$failCost = travelCost('Car', 90);

Werte

Standardmäßig werden Aufzählungen nicht durch irgendeine Art von Skalar unterstützt. Daher TransportMode::Bicycle ist nicht 0 und Sie können nicht vergleichen mit > o < zwischen den Aufzählungen.

Aber das Folgende funktioniert:

$foo = TransportMode::Car;
$bar = TransportMode::Car;
$baz = TransportMode::Bicycle;

$foo === $bar; // true
$bar === $baz; // false

$foo instanceof TransportMode; // true

$foo > $bar || $foo <  $bar; // false either way

Gesicherte Aufzählungen

Sie können auch "unterstützte" Aufzählungen haben, bei denen jeder Aufzählungsfall entweder durch eine "unterstützte" int oder eine string .

enum Metal: int {
  case Gold = 1932;
  case Silver = 1049;
  case Lead = 1134;
  case Uranium = 1905;
  case Copper = 894;
}
  • Wenn ein Fall einen gesicherten Wert hat, müssen alle Fälle einen gesicherten Wert haben; es gibt keine automatisch generierten Werte.
  • Beachten Sie, dass der Typ des rückgesicherten Wertes direkt nach dem Aufzählungsnamen angegeben wird
  • Gesicherte Werte sind nur lesen
  • Skalare Werte müssen sein einzigartig
  • Die Werte müssen Literale oder wörtliche Ausdrücke sein.
  • Um den gesicherten Wert zu lesen, greifen Sie auf die value Eigentum: Metal::Gold->value .

Schließlich implementieren die unterstützten Aufzählungen eine BackedEnum Schnittstelle, die zwei Methoden zur Verfügung stellt:

  • from(int|string): self
  • tryFrom(int|string): ?self

Sie sind fast gleichwertig, mit dem wichtigen Unterschied, dass die erste eine Ausnahme auslöst, wenn der Wert nicht gefunden wird, und die zweite gibt einfach null .

// usage example:

$metal_1 = Metal::tryFrom(1932); // $metal_1 === Metal::Gold;
$metal_2 = Metal::tryFrom(1000); // $metal_2 === null;

$metal_3 = Metal::from(9999); // throws Exception

Methoden

Aufzählungen können Methoden haben und somit Schnittstellen implementieren.

interface TravelCapable
{
    public function travelCost(int $distance): int;
    public function requiresFuel(): bool;
}

enum TransportMode: int implements TravelCapable{
  case Bicycle = 10;
  case Car = 1000 ;
  case Ship = 800 ;
  case Plane = 2000;
  case Feet = 5;

  public function travelCost(int $distance): int
  {
    return $this->value * $distance;
  }

  public function requiresFuel(): bool {
    return match($this) {
        TransportMode::Car, TransportMode::Ship, TransportMode::Plane => true,
      TransportMode::Bicycle, TransportMode::Feet => false
    }
  }
}

$mode = TransportMode::Car;

$carConsumesFuel = $mode->requiresFuel();   // true
$carTravelCost   = $mode->travelCost(800);  // 800000

Werteliste

Sowohl Pure Enums als auch Backed Enums implementieren intern die Schnittstelle UnitEnum , die die (statische) Methode UnitEnum::cases() und ermöglicht den Abruf eines Arrays der in der Aufzählung definierten Fälle:

$modes = TransportMode::cases();

Und jetzt $modes ist:

[
    TransportMode::Bicycle,
    TransportMode::Car,
    TransportMode::Ship,
    TransportMode::Plane
    TransportMode::Feet
]

Statische Methoden

Aufzählungen können ihre eigenen static Methoden, die im Allgemeinen für spezialisierte Konstruktoren verwendet werden.


Damit sind die Grundlagen abgedeckt. Um alles zu erfahren, besuchen Sie bitte die entsprechender RFC bis die Funktion freigegeben und in der PHP-Dokumentation veröffentlicht wird.

50voto

Peter Bailey Punkte 103278

Was ist mit Klassenkonstanten?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

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

echo YourClass::SOME_CONSTANT;

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

44voto

andy.gurin Punkte 3766

Ich habe Klassen mit Konstanten verwendet:

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

print Enum::NAME;

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