PHP ve numaralandırma

22 Cevap php

Ben PHP yerli Enumeration olmadığını biliyoruz. Ama Java dünyasında onlara alışmış. Ben Ides 'otomatik tamamlama özellikleri anlayabileceği önceden tanımlanmış değerler vermek için bir yol olarak çeteleler kullanmak isterdim.

Sabitleri hile yapmak, ancak ad çarpışma sorunu ve (ya da aslında because) küresel konum var. Diziler namespace sorun yok, ama onlar da belirsiz konum, onlar zamanında yazılmasını ve IDE nadiren (hiç?) Kendi anahtarlarını autofill için biliyorum.

Eğer sık ​​kullandığınız herhangi bir çözüm / geçici çözüm var mı? Herkes PHP adamlar çeteleler etrafında herhangi bir düşünce veya kararlar vardı olmadığını hatırlamak mı?

22 Cevap

: Kullanım durumunda bağlı olarak, normalde bir şey simple aşağıdaki gibi kullanabilirsiniz

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

$today = DaysOfWeek::Sunday;

(Edit on 2013-12-12)

Ancak, diğer kullanım durumları sabitler ve değerlerin daha doğrulama gerekebilir. Yansıması, ve birkaç diğer notları hakkında aşağıda yorumlarına dayanarak, burada daha iyi durumlarda çok daha geniş bir yelpazede hizmet edebilir genişletilmiş bir örnek:

abstract class BasicEnum {
    private static $constCache = NULL;

    private static function getConstants() {
        if (self::$constCache === NULL) {
            $reflect = new ReflectionClass(get_called_class());
            self::$constCache = $reflect->getConstants();
        }

        return self::$constCache;
    }

    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) {
        $values = array_values(self::getConstants());
        return in_array($value, $values, $strict = true);
    }
}

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

BasicEnum uzanan basit bir numaralama sınıf oluşturarak, artık basit giriş doğrulaması için bu suretle yöntemleri kullanmak için yeteneği var:

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

Taze yansıma kullanarak nesneleri beri bir yan not olarak, ben on a static/const class where the data won't change (böyle bir enum gibi) en az bir kez yansıması kullanmak her zaman, ben her zaman sonunda farkedilir bir performans olacak, bu yansıma aramaların sonuçlarını önbelleğe etkisi.

Şimdi çoğu kişi finally en az 5.3 yükseltilmiş, ve SplEnum mevcut olması, bu da kesinlikle uygulanabilir bir seçenektir - sürece geleneksel unintuitive sakıncası yok gibi senin kod tabanı boyunca gerçek enum instantiations sahip kavramı. Yukarıdaki örnekte, BasicEnum ve DaysOfWeek tüm örneği değildir, ne de olmalıdır.

Yerel bir uzantı da bulunmaktadır. SplEnum

SplEnum gives the ability to emulate and create enumeration objects natively in PHP.

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

Ne sınıf sabitleri hakkında?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

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

echo YourClass::SOME_CONSTANT;

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

Ben kullanmak interface yerine class:

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

var $today = DaysOfWeek::Sunday;

Peki, php enum gibi basit java için ben kullanın:

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

And to call it: SomeTypeName::toOrdinal("Read"); SomeTypeName::toString(1);

Ama ben bu yüzden en iyi yol olmayabilir sözdizimi ile mücadele, bir PHP acemi değilim. Ben, bu değer sabiti adını almak için kıvrımlara olabilir Yansıma kullanarak, Sınıf sabitleri ile bazı deneyler.

Ben sabitleri ile sınıflar kullanılabilir:

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

print Enum::NAME;

Sen ve kullanımı kolay, aşağıdaki kodu kullanmak için çekinmeyin (farklı numaralamalar arasındaki öğeleri karşılaştırarak bile yani) genel olarak benzersizdir çeteleler kullanmanız gerekir. Ben de yararlı bazı yöntemler eklendi. Sen kod çok üstünde açıklamalarda örnekler bulacaksınız.

<?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 $_ A list of strings to use as names for enum entries
     */
    public static function Create($name, $_)
    {
        // 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";
    }

}


?>

Ben de java dan Çeteleler seviyorum ve ben bu şekilde benim Çeteleler yazmak, bu nedenle, bazı java daha yöntemleri kullanmak istiyorsanız tabii ki, buraya yazmak gerektiğini, bu Java çeteleler gibi en benzer behawior olduğunu düşünüyorum, ya da soyut bir sınıf ancak çekirdek fikri aşağıdaki kodu gömülü olduğu


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

İşte php tip-güvenli numaralandırma işlemek için bir github kütüphane:

Bu kütüphane kolu sınıfları nesil, sınıflar önbelleğe alma ve enums kombinasyonları için, sıralama, ya da bir ikili değer almak Numaralamalar için bir sıralı alma gibi çeteleler ile başa çıkmak için çeşitli yardımcı yöntemler ile, Tip Güvenli Numaralama tasarım deseni uygular.

Oluşturulan kod da yapılandırılabilir bir düz eski php şablon dosyasını kullanabilirsiniz, böylece kendi şablonu sağlayabilir.

Bu PHPUnit ile kaplı tam testtir.

php-enums on github (feel free to fork)

Usage: (@see usage.php, or unit tests for more details)

<?php
//require the library
require_once __DIR__ . '/src/Enum.func.php';

//if you don't have a cache directory, create one
@mkdir(__DIR__ . '/cache');
EnumGenerator::setDefaultCachedClassesDir(__DIR__ . '/cache');

//Class definition is evaluated on the fly:
Enum('FruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'));

//Class definition is cached in the cache directory for later usage:
Enum('CachedFruitsEnum', array('apple' , 'orange' , 'rasberry' , 'bannana'), '\my\company\name\space', true);

echo 'FruitsEnum::APPLE() == FruitsEnum::APPLE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::APPLE()) . "\n";

echo 'FruitsEnum::APPLE() == FruitsEnum::ORANGE(): ';
var_dump(FruitsEnum::APPLE() == FruitsEnum::ORANGE()) . "\n";

echo 'FruitsEnum::APPLE() instanceof Enum: ';
var_dump(FruitsEnum::APPLE() instanceof Enum) . "\n";

echo 'FruitsEnum::APPLE() instanceof FruitsEnum: ';
var_dump(FruitsEnum::APPLE() instanceof FruitsEnum) . "\n";

echo "->getName()\n";
foreach (FruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getName() . "\n";
}

echo "->getValue()\n";
foreach (FruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getValue() . "\n";
}

echo "->getOrdinal()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getOrdinal() . "\n";
}

echo "->getBinary()\n";
foreach (CachedFruitsEnum::iterator() as $enum)
{
  echo "  " . $enum->getBinary() . "\n";
}

Output:

FruitsEnum::APPLE() == FruitsEnum::APPLE(): bool(true)
FruitsEnum::APPLE() == FruitsEnum::ORANGE(): bool(false)
FruitsEnum::APPLE() instanceof Enum: bool(true)
FruitsEnum::APPLE() instanceof FruitsEnum: bool(true)
->getName()
  APPLE
  ORANGE
  RASBERRY
  BANNANA
->getValue()
  apple
  orange
  rasberry
  bannana
->getValue() when values have been specified
  pig
  dog
  cat
  bird
->getOrdinal()
  1
  2
  3
  4
->getBinary()
  1
  2
  4
  8

Ben hemen hemen tüm çözümler elle enum öğelerin değerlerini atamak gerektirir beri ancak gördüğüm geçici çözümlerden hiçbiri gerçekten, çeteleler gibi görünüyordu, bu eski bir konu olduğunu biliyorum, ya da bir enum için tuşları bir dizi geçmek gerekir fonksiyonu. Yani bu benim kendi çözüm yarattı.

Biri sadece statik değişken bir demet (onları başlatmaya gerek yok) oluşturmak, aşağıda bu Enum sınıfı genişletmek ve sadece enum sınıfın tanımı altında yourEnumClass için bir çağrı :: init () yapabilir benim çözüm kullanarak bir enum sınıf oluşturmak .

edit: This only works in php >= 5.3, but it can probably be modified to work in older versions as well

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

I've commented on some of the other answers here, so I figured I would weigh in too. At the end of the day, since PHP doesn't support typed enumerations, you can go one of two ways: hack out typed enumerations, or live with the fact that they're extremely difficult to hack out effectively.

Ben gerçeği ile yaşamayı tercih ve yerine başka bir cevap burada bazı şekilde ya da başka kullanmış const yöntemi kullanın:

abstract class Enum
{

    const NONE = null;

    final private function __construct()
    {
        ; // non-constructable
    }

    final private function __clone()
    {
        ; // non-cloneable
    }

    final public static function toArray()
    {
        return (new \ReflectionClass(get_called_class()))->getConstants();
    }

    final public static function isValid($value)
    {
        return in_array($value, static::toArray());
    }

}

Bir örnek numaralandırma:

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;

}

Enum diğer numaralandırma uzandığı bir temel sınıf benzeri gibi yardımcı toArray, isValid gibi yöntemlerle, ve sağlar olarak kullanılması. Bana göre, (and managing their instances) sadece çok dağınık sona numaralandırma yazdınız.


Hypothetical

If, bu çok multiton desen bir tür ile hafifletilebilir bir __getStatic sihirli yöntemi (çok and preferably an __equals sihirli yöntemi) orada var.

(The following is hypothetical; it won't iş olsa belki bir gün o olacak )

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

PHP bulunuyor enum gördük en yaygın çözüm genel bir enum sınıf oluşturmak ve daha sonra bunu genişletmek olmuştur. Sen this bakmak olabilir.

UPDATE: Alternatif olarak, I-this phpclasses.org bulundu.

Kabul cevabı gitmek için bir yoldur ve ben basitlik için ne yapıyorum aslında. Numaralandırma çoğu avantajları (okunabilir, hızlı, vb) sunulmaktadır. Bir kavram, ancak eksik: tip güvenliği. Çoğu dilde, numaralandırma da izin değerleri sınırlamak için kullanılır. Aşağıda tip güvenliği de özel Kurucular, statik örnekleme yöntemleri ve tip kontrolü kullanılarak elde edilebilir nasıl bir örnek:

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

Hatta daha ileri gidebiliriz: DaysOfWeek sınıfında sabitler kullanarak hor neden olabilir: örneğin, biri yanlışlıkla bu şekilde kullanabilirsiniz:

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

Yanlış olan (tamsayı sabit aramaları). Biz yerine sabitler özel statik değişkenleri kullanarak bu önleyebilirsiniz:

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

}

Tabii ki, (bu aslında amacı neydi) tamsayı sabitleri erişmek mümkün değildir. Intval yöntemi, tamsayı gösterimine DaysOfWeek nesneyi dönüştürmek sağlar.

Biz bile yaygın olarak kullanılan durumda numaralandırma hafızayı kaydetmek için örnekleme yöntemleri bir önbelleğe alma mekanizması uygulayarak ileri gidebiliriz unutmayın ...

Bu yardımcı olacağını umuyoruz

Bana işlev parametreleri tür güvenliği için yetenek, NetBeans tam otomatik ve iyi performans verir gibi ben aşağıdaki yaklaşımı kullanarak almış. Ben çok fazla sevmiyorum tek şey sınıf tanımladıktan sonra [extended class name]::enumerate(); çağırmak zorunda olmasıdır.

abstract class Enum {

    private $_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");

I değişkenler, eski ile çağırabilirsiniz, böylece bu ... "dinamik" enum almak benim. bir form.

look at updated verison below this 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);
    }
}

UPDATE: Better way of doing it...

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;

}

Ile arayın

EnumCategory::${$category};

Dün bu sınıf yazdım on my blog. Ben belki php komut kullanımı kolay olacağını düşünüyorum:

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

Kullanımı:

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

Işaret çözüm iyi çalışıyor. Temiz ve pürüzsüz.

Eğer güçlü yazdığınız numaralandırma istiyorsanız Ancak, bunu kullanabilirsiniz:

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

Bir Enum sınıfı gibi bakarak:

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

Bu şekilde, enum değerler kesin belirlenmiş ve vardır

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

Burada bazı iyi çözümler!

İşte benim sürümü bulunuyor.

  • Bu güçlü daktilo
  • Bu IDE otomatik tamamlama ile çalışır
  • Numaralamalar kod ve kod istediğiniz bir tamsayı, bir ikili değer, kısa bir dize ya da temelde başka bir şey olabilir bir açıklama ile tanımlanır. Desen kolayca orther özelliklerini desteklemek için uzun olabilir.
  • Bu (==) değerini asupports ve switch ifadeleri referans (===) karşılaştırmalar ve eserleri.

Ben ana dezavantajı enum üyeleri ayrı ayrı ilan nedeniyle açıklamaları ve statik üyesi bildirimi zamanında nesneleri oluşturmak için PHP'nin yetersizlik, örneği zorunda olduğunu düşünüyorum. Ben bu yuvarlak bir şekilde yerine çözümlü doc yorumlarla yansıması kullanmak için olabilir sanırım.

Soyut enum bu gibi görünüyor:

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

İşte bir örnek beton enum bulunuyor:

<?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, 'Benim ikinci değer');
        self::$MY_THIRD_VALUE = self::enum(3, 'My third value');
    }
}

EMyEnum::_init();

Bu gibi kullanılabilir Hangi:

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

Ve bu çıktıyı üretir:

1: İlk değeri

array(3) {
[1]=>
object(EMyEnum)#1 (2) {
["code":"AbstractEnum":private]=>
int(1)
["description":"AbstractEnum":private]=>
string(14) "My first value"
}
[2]=>
object(EMyEnum)#2 (2) {
["code":"AbstractEnum":private]=>
int(2)
["description":"AbstractEnum":private]=>
string(15) "Benim ikinci değer"
}
[3]=>
object(EMyEnum)#3 (2) {
["code":"AbstractEnum":private]=>
int(3)
["description":"AbstractEnum":private]=>
string(14) "My third value"
}
}

Benim ikinci değer

I this library github bulunan ve ben burada cevaplar için çok iyi bir alternatif sunuyor düşünüyorum.

PHP Enum implementation inspired from SplEnum

  • Şunları yapabilirsiniz tip-ipucu: function setAction(Action $action) {
  • Bu yöntemlerle enum zenginleştirmek (örn. format, parse, ...)
  • Yeni değerleri (sizin enum yapmak final bunu önlemek için) eklemek için enum uzatabilirsiniz
  • (Aşağıya bakınız), tüm olası değerlerin bir listesini alabilirsiniz

Declaration

<?php
use MyCLabs\Enum\Enum;

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

Usage

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

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

type-hint enum values:

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

Ben basit Numaralamalar için aşağıdaki gibi bir yapı kullanabilirsiniz. Genellikle switch ifadeleri için bunları kullanabilirsiniz.

<?php 
  define("OPTION_1", "1");
  define("OPTION_2", OPTION_1 + 1);
  define("OPTION_3", OPTION_2 + 1);

  // Some function...
   switch($Val){
    case OPTION_1:{ Perform_1();}break;
    case OPTION_2:{ Perform_2();}break;
    ...
  }
?>

Bu kadar conviniet C + + gibi bir yerli enum olarak değil ama iş gibi görünüyor ve daha sonra aralarında bir seçenek eklemek istiyorum eğer daha az bakım gerektirir.

Bu enum değerler olarak ama yine de biraz yararlı nesneleri desteklemiyor beri PHP ile bir enum oluşturmak için benim girişimi ... son derece sınırlı oluyor ...

class ProtocolsEnum {

    const HTTP = '1';
    const HTTPS = '2';
    const FTP = '3';

    /**
     * Retrieve an enum value
     * @param string $name
     * @return string
     */
    public static function getValueByName($name) {
        return constant('self::'. $name);
    } 

    /**
     * Retrieve an enum key name
     * @param string $code
     * @return string
     */
    public static function getNameByValue($code) {
        foreach(get_class_constants() as $key => $val) {
            if($val == $code) {
                return $key;
            }
        }
    }

    /**
     * Retrieve associate array of all constants (used for creating droplist options)
     * @return multitype:
     */
    public static function toArray() {      
        return array_flip(self::get_class_constants());
    }

    private static function get_class_constants()
    {
        $reflect = new ReflectionClass(__CLASS__);
        return $reflect->getConstants();
    }
}

Yukarıda üst cevaptır harika. Eğer iki farklı şekilde uzatmak, ancak daha sonra işlevleri bir çağrı hangisi ilk sonuçlar daha sonra aramalar tarafından başlatılan hangisi uzatma tüm sonraki çağrı tarafından kullanılacak cahce yaratacak ...

Bunu çözmek için, ile değişken ve ilk işlev değiştirin:

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