장점 - PHP와 열거 형




열거형 장점 (20)

4 년 후 나는 이것을 다시 보았습니다. 현재 접근 방식은 IDE에서 코드 완성과 유형 안전을 허용하므로 다음과 같습니다.

기본 클래스 :

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

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

사용 예 :

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

동일한 enum 항목의 모든 인스턴스가 동일하다는 점에 유의하십시오.

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

switch 문 내부에서도 사용할 수 있습니다.

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

이름이나 값으로 열거 형 항목을 만들 수도 있습니다.

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

또는 기존 enum 항목에서 이름 (즉 함수 이름)을 얻을 수 있습니다.

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

나는 PHP가 네이티브 열거 형을 가지고 있지 않다는 것을 알고있다. 그러나 저는 자바 세계에서 그들에게 익숙해졌습니다. IDE의 자동 완성 기능이 이해할 수있는 미리 정의 된 값을 제공하는 방법으로 열거 형을 사용하고 싶습니다.

상수는 속임수를 쓰지 만 네임 스페이스 충돌 문제가 있으며 (또는 실제로 인해 ) 전역 적입니다. 배열은 네임 스페이스 문제가 없지만 너무 모호합니다. 런타임에 덮어 쓸 수 있으며 IDE는 키를 자동 완성하는 방법을 거의 알지 못합니다.

일반적으로 사용하는 솔루션 / 해결 방법이 있습니까? 열심히 PHP 남자들이 enums에 대한 생각이나 결정을했는지를 기억 하나?


그것은 다음과 같이 간단 할 수 있습니다.

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

미래에.

PHP RFC : 열거 형


나는 github.com/myclabs/php-enum 를 github에서 발견했으며, 여기에 대한 답을 대체할만한 대체품을 제공한다고 생각합니다.

SplEnum에서 영감을 얻은 PHP Enum 구현

  • 입력 힌트 : function setAction(Action $action) {
  • 열거 형을 메서드 (예 : format , parse , ...)로 풍부하게 만들 수 있습니다.
  • 열거 형을 확장하여 새 값을 추가 할 수 있습니다 (열거 형을 막아 final 를 방지 할 수 있음)
  • 가능한 모든 값 목록을 얻을 수 있습니다 (아래 참조).

선언

<?php
use MyCLabs\Enum\Enum;

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

용법

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

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

type-hint 열거 형 값 :

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

나는 상수와 함께 클래스를 사용했다 :

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

print Enum::NAME;

나는 자바로부터 열거 형을 좋아한다. 그래서 이런 식으로 열거 형을 작성한다. 자바에서 더 많은 메소드를 사용하고자한다면 자바 enums에서와 같이 가장 친숙한 behawior라고 생각한다. 추상 클래스이지만 핵심 아이디어는 아래 코드에 임베드되어 있습니다.


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


난 거의 모든 해결 방법을 열거 항목에 값을 수동으로 지정해야합니다 또는 열거 형처럼 열심히 보였다 해결 방법 중 하나를 오래된 스레드 알지만 열거 형 키 배열을 전달할 필요합니다. 기능. 그래서 저는 이것을위한 자체 솔루션을 만들었습니다.

내 솔루션을 사용하여 enum 클래스를 만들려면이 Enum 클래스를 다음과 같이 확장하고 정적 변수를 여러 개 만들고 (초기화 할 필요가 없음) enum 클래스 정의 바로 아래에서 yourEnumClass :: init ()을 호출하면됩니다. .

편집 : 이것은 php> = 5.3에서만 작동하지만 이전 버전에서도 잘 작동하도록 수정 될 수 있습니다

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

다음은 php에서 타입 - 안전한 enumeration을 처리하기위한 github 라이브러리입니다 :

이 라이브러리는 클래스 생성, 클래스 캐싱을 처리하며 열거 형 정렬을위한 서수 검색 또는 열거 형 조합의 이진 값 검색과 같이 열거 형을 다루는 여러 가지 도우미 메서드가있는 유형 안전 열거 형 디자인 패턴을 구현합니다.

생성 된 코드는 구성 가능한 일반 old PHP 템플릿 파일을 사용하므로 사용자가 직접 템플릿을 제공 할 수 있습니다.

그것은 phpunit로 덮여 전체 테스트입니다.

github에서 php-enums (포크를 자유롭게 사용함)

사용법 : (자세한 내용은 @see usage.php 또는 단위 테스트를 참조하십시오)

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

산출:

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

위의 대답은 환상적입니다. 그러나 두 가지 방법으로 확장하면 함수를 호출 한 첫 번째 결과의 확장이 캐시를 생성합니다. 이 캐시는 이후의 모든 호출에 의해 사용되며, 확장자에 관계없이 호출이 시작됩니다.

이 문제를 해결하려면 변수와 첫 번째 함수를 다음으로 대체하십시오.

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

전역 적으로 고유 한 열거 형을 사용해야하는 경우 (즉 여러 Enum 사이의 요소를 비교할 때조차도) 사용하기 쉽고 다음 코드를 자유롭게 사용하십시오. 또한 유용한 몇 가지 방법을 추가했습니다. 주석의 맨 위에있는 예제를 찾을 수 있습니다.

<?php

/**
 * Class Enum
 * 
 * @author Christopher Fox <[email protected]>
 *
 * @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";
    }

}


?>

클래스 상수는 어떻습니까?

<?php

class YourClass
{
    const SOME_CONSTANT = 1;

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

echo YourClass::SOME_CONSTANT;

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

필자는 기능 매개 변수에 대한 유형 안전성, NetBeans의 자동 완성 및 우수한 성능을 제공 할 수 있으므로 아래 접근법을 사용했습니다. 내가 너무 좋아하지 않는 한가지는 [extended class name]::enumerate(); 를 호출해야한다는 것입니다 [extended class name]::enumerate(); 클래스를 정의한 후

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

class 대신 interface 를 사용합니다.

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

var $today = DaysOfWeek::Sunday;

PHP로 열거 형을 만드는 나의 시도 ... 열거 형 값으로 객체를 지원하지 않기 때문에 극히 제한적이지만 여전히 유용합니다 ...

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

여기 다른 답변에서 빠진 측면 중 하나는 유형 힌트와 함께 enum을 사용하는 방법입니다.

enum을 추상 클래스의 상수 집합으로 정의하면 (예 :

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

당신은 함수 매개 변수에 힌트 입력 할 수 없습니다 - 하나, 그것은 인스턴스화 아니기 때문에, 또한 유형이 있기 때문 ShirtSize::SMALL이다 int,하지 ShirtSize.

그렇기 때문에 PHP의 기본 열거 형은 우리가 생각해 낼 수있는 것보다 훨씬 낫습니다. 그러나 열거 형 값을 나타내는 전용 속성을 유지 한 다음이 속성의 초기화를 미리 정의 된 상수로 제한하여 열거 형을 근사값으로 지정할 수 있습니다. 열거 형이 임의로 인스턴스화되는 것을 방지하기 위해 (화이트리스트를 유형 검사하는 오버 헤드없이) 생성자를 private으로 만듭니다.

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

그러면 다음 ShirtSize과 같이 사용할 수 있습니다 .

function sizeIsAvailable ($productId, ShirtSize $size) {
    // business magic
}
if(sizeIsAvailable($_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";

이 방법은 사용자 관점에서 가장 큰 차이점 ()은 상수의 이름 을 붙잡아 야한다는 것 입니다.

한 가지 단점은 ===(객체 평등을 비교하는) true를 ==반환 할 때 false를 반환 한다는 것 입니다. equals따라서 사용자가 두 열거 형 값을 비교 ==하지 않고 사용하는 것을 기억할 필요가 없도록 메서드 를 제공하는 것이 가장 좋습니다 ===.

편집 : 기존의 몇 가지 답변은 매우 유사, 특히 : https://.com/a/25526473/2407870 .


이것이 아주 아주 오래된 쓰레드라는 것을 알았지 만 이것에 대해 생각해 보았고 사람들이 생각한 것을 알고 싶었습니다.

Notes : 나는 이것으로 놀고 있었고, 만약 __call()당신이 실제와 더 가까워 질 수 있는 함수를 수정했다면 깨달았다 enums. 이 __call()함수는 모든 알 수없는 함수 호출을 처리합니다. 그럼 enumsRED_LIGHT, YELLOW_LIGHT 및 GREEN_LIGHT 세 가지를 만들 겠다고합시다. 다음과 같이하면됩니다.

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

일단 정의 된 후에 다시 호출하여 값을 얻습니다.

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

0, 1, 2가되어야합니다. 즐겁게 보내십시오! 이것은 GitHub에도 올라 있습니다.

업데이트 : 나는 그것을 만들었고 함수 __get()__set()함수가 모두 사용되도록했습니다. 이것들은 당신이 원하지 않는 한 당신이 함수를 호출 할 필요가 없다. 대신 이제는 다음과 같이 말할 수 있습니다.

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

값의 생성과 가져 오기 모두. 변수가 처음에 정의되지 않았 __get()으므로 배열의 항목이 작성되지 않았 음을 알리는 함수가 호출됩니다 (값이 지정되지 않았으므로). 그래서 엔트리를 만들고, 주어진 마지막 값에 +1을 더하고, 마지막 값 변수를 증가시키고, TRUE를 반환합니다. 값을 설정하는 경우 :

$c->RED_LIGHT = 85;

그런 다음 __set()함수가 호출되고 마지막 값에 새 값 +1 (+1)이 설정됩니다. 그래서 우리는 열거 형을 수행하는 꽤 좋은 방법을 가지고 있으며 즉시 생성 될 수 있습니다.

<?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
#           [email protected]  :-)
#
#   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";

?>

나는 Brian Cline의 대답에 기반한 라이브러리를 만들었고, greg0ire/enum 이라는 이름을 greg0ire/enum Enjoy!


어제 저는이 블로그를 제 블로그에 썼습니다 . 나는 아마 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;
    }
}

용법:

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

이것은 "동적"enum ...에 대한 필자의 생각입니다. 그래서 저는 변수로 호출 할 수 있습니다. 양식에서.

이 코드 블록 아래에서 업데이트 된 버전을 확인하십시오 ...

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

업데이트 : 그것을하는 더 나은 방법 ...

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;

}

전화 걸기

EnumCategory::${$category};

지적 솔루션은 잘 작동합니다. 깨끗하고 부드러운.

그러나 강력하게 형식화 된 열거 형을 원하면 다음을 사용할 수 있습니다.

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

Enum 클래스는 다음과 같습니다.

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

이렇게하면 열거 형 값은 강력하게 형식화되며

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


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




enumeration