복붙노트

PHP와 열거 형

PHP

PHP와 열거 형

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

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

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

해결법

  1. ==============================

    1.유스 케이스에 따라, 나는 보통 다음과 같은 간단한 것을 사용할 것이다.

    유스 케이스에 따라, 나는 보통 다음과 같은 간단한 것을 사용할 것이다.

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

    그러나 다른 유스 케이스에서는 상수와 값의 유효성 검사가 더 필요할 수 있습니다. 리플렉션에 대한 아래 설명과 몇 가지 다른 참고 사항을 기반으로, 여기에는 광범위한 사례를 효과적으로 제공 할 수있는 확장 된 예가 나와 있습니다.

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

    BasicEnum을 확장하는 간단한 enum 클래스를 작성하면 간단한 입력 유효성 검사에 메소드를 사용할 수 있습니다.

    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
    

    참고로, 언제든지 (예 : enum) 데이터가 변경되지 않는 정적 / const 클래스에서 적어도 한 번 반사를 사용할 때마다 새 반사 객체를 사용할 때마다 해당 반사 호출의 결과를 캐시합니다. 궁극적으로 눈에 띄는 성능 영향을 미칠 것입니다 (여러 enum에 대한 assocciative 배열에 저장).

    이제는 대부분의 사람들이 마침내 5.3 이상으로 업그레이드되었으며 SplEnum도 사용할 수 있습니다. 이는 코드베이스에서 실제 enum 인스턴스화를 사용하지 않는 전통적이지 않은 개념에 신경 쓰지 않는 한 확실히 확실합니다. 위 예제에서 BasicEnum과 DaysOfWeek은 전혀 인스턴스화 될 수 없으며 인스턴스화 될 수도 없습니다.

  2. ==============================

    2.네이티브 확장도 있습니다. SplEnum

    네이티브 확장도 있습니다. SplEnum

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

  3. ==============================

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

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

    <?php
    
    class YourClass
    {
        const SOME_CONSTANT = 1;
    
        public function echoConstant()
        {
            echo self::SOME_CONSTANT;
        }
    }
    
    echo YourClass::SOME_CONSTANT;
    
    $c = new YourClass;
    $c->echoConstant();
    
  4. ==============================

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

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

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

    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];
    }
    
  5. ==============================

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

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

    class Enum {
        const NAME       = 'aaaa';
        const SOME_VALUE = 'bbbb';
    }
    
    print Enum::NAME;
    
  6. ==============================

    6.클래스 대신 인터페이스를 사용합니다.

    클래스 대신 인터페이스를 사용합니다.

    interface DaysOfWeek
    {
        const Sunday = 0;
        const Monday = 1;
        // etc.
    }
    
    var $today = DaysOfWeek::Sunday;
    
  7. ==============================

    7.글쎄, PHP에서 enum 같은 간단한 자바 들어, 내가 사용 :

    글쎄, PHP에서 enum 같은 간단한 자바 들어, 내가 사용 :

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

    그리고 그것을 부른다 :

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

    그러나 나는 PHP 초보자이기 때문에 구문에 어려움을 겪고 있기 때문에 이것이 최선의 방법은 아닙니다. 클래스 상수와 함께 실험 해 보았습니다. 리플렉션을 사용하여 상수 이름을 얻었습니다.

  8. ==============================

    8.나는 여기에 다른 대답들에 대해 논평했다. 그래서 나는 또한 체중을 줄 것이라고 생각했다. PHP는 형식화 된 열거 형을 지원하지 않으므로 하루 종일 열거 형을 해킹하거나 실제로 해킹하기가 매우 어렵다는 두 가지 방법 중 하나를 선택할 수 있습니다.

    나는 여기에 다른 대답들에 대해 논평했다. 그래서 나는 또한 체중을 줄 것이라고 생각했다. PHP는 형식화 된 열거 형을 지원하지 않으므로 하루 종일 열거 형을 해킹하거나 실제로 해킹하기가 매우 어렵다는 두 가지 방법 중 하나를 선택할 수 있습니다.

    나는 사실과 함께 사는 것을 선호한다. 대신 const 메소드를 사용하여 다른 응답이 어떤 식 으로든 사용되었다.

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

    예제 열거 :

    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을 사용하면 toArray, isValid 등과 같은 도우미 메서드가 허용됩니다. 나에게 입력 된 열거 형 (및 인스턴스 관리)이 너무 복잡해진다.

    만약, __getStatic 매직 메소드 (그리고 바람직하게는 __equals 매직 메소드도 있음)가 있다면, 이것의 대부분은 일종의 멀티 톤 패턴으로 완화 될 수 있습니다.

    (다음은 가설적인 것이며 작동하지는 않지만 언젠가는 가능할 것입니다)

    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
    
  9. ==============================

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

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

    또는 기존 열거 형 항목에서 이름 (예 : 함수 이름)을 얻을 수 있습니다.

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

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

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

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

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

    나는 자바로부터 열거 형을 좋아한다. 그래서 이런 식으로 열거 형을 작성한다. 자바에서 더 많은 메소드를 사용하고자한다면 자바 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
    
    
  12. ==============================

    12.필자가 PHP에서 enum을 보았던 가장 일반적인 해결책은 일반적인 enum 클래스를 만든 다음 확장하는 것입니다. 이것 좀 봐.

    필자가 PHP에서 enum을 보았던 가장 일반적인 해결책은 일반적인 enum 클래스를 만든 다음 확장하는 것입니다. 이것 좀 봐.

    업데이트 : 또는 phpclasses.org에서이 파일을 발견했습니다.

  13. ==============================

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

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

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

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

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

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

    <?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
    
  14. ==============================

    14.

    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>";
    }
    
  15. ==============================

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

    필자는 기능 매개 변수에 대한 유형 안전성, NetBeans의 자동 완성 및 우수한 성능을 제공 할 수 있으므로 아래 접근법을 사용했습니다. 내가 너무 좋아하지 않는 한가지는 [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");
    
  16. ==============================

    16.나는이 라이브러리를 github에서 발견했으며, 여기에 대한 답을 대체할만한 대체품을 제공한다고 생각합니다.

    나는이 라이브러리를 github에서 발견했으며, 여기에 대한 답을 대체할만한 대체품을 제공한다고 생각합니다.

    <?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();
    
    <?php
    function setAction(Action $action) {
        // ...
    }
    
  17. ==============================

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

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

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

    미래에.

    PHP RFC : 열거 형

  18. ==============================

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

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

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

    편집 : 이것은 php> = 5.3에서만 작동하지만 이전 버전에서도 잘 작동하도록 수정 될 수 있습니다      / **  enum을위한 기본 클래스.  *  *이 클래스는 열거 형의 기본 클래스로 사용할 수 있습니다.  * 일반 열거 형 (증분 인덱스)을 만드는 데 사용할 수 있지만 이진 플래그 값을 만드는 데에도 사용할 수 있습니다.  * enum 클래스를 만들려면이 클래스를 확장하고 열거 형을 사용하기 전에 :: init ()을 호출하면됩니다.  *이 호출은 클래스 선언 바로 뒤에 수행하는 것이 바람직합니다.  * 예제 사용법 :  * DaysOfTheWeek.class.php  * 추상 클래스 DaysOfTheWeek는 Enum {  정적 $ 월요일 = 1;  정적 $ TUESDAY;  정적 $ 수요일;  * 정적 $ 목요일;  정적 $ 금요일;  * 정적 $ 토요일;  정적 $ 일요일;  *}  * 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 클래스 Flags extends Enum {  * 정적 $ FLAG_1;  정적 $ FLAG_2;  * 정적 $ FLAG_3;  *}  * Flags :: init (열거 형 :: $ BINARY_FLAG);  *  * example2.php  * require_once ( "Flags.class.php");  * $ flags = 플래그 :: $ FLAG_1 | Flags :: $ FLAG_2;  * if ($ 플래그 및 플래그 :: $ FLAG_1)  * echo "Flag_1이 (가) 설정되었습니다";  *  * @author Tiddo Langerak  * / abstract 클래스 Enum {     정적 $ BINARY_FLAG = 1;     / **      * 열거 형을 초기화하려면이 함수를 호출해야합니다!      *      * @param bool $ flags USE_BINARY 플래그가 제공되면 enum 값은 2 진 플래그 값이됩니다. 기본값 : 플래그가 설정되지 않습니다.      * /     public static function init ($ 플래그 = 0) {         // 먼저, enum 클래스의 모든 정적 속성 목록을 가져 오려고합니다. ReflectionClass를 사용합니다.         $ enum = get_called_class ();         $ ref = new ReflectionClass ($ enum);         $ items = $ ref-> getStaticProperties ();         // 이제 항목에 값을 할당 할 수 있습니다.         if ($ flags & self :: $ BINARY_FLAG) {             // 바이너리 플래그 값을 원하면 첫 번째 값은 1이어야합니다.             $ 값 = 1;             // 이제 모든 항목의 값을 설정할 수 있습니다.             foreach ($ items는 $ key => $ item) {                 if (! isset ($ item)) {                     // 값을 수동으로 설정하지 않으면 설정해야합니다.                     $ enum :: $$ key = $ value;                     // 그리고 새 값을 계산해야합니다.                     $ 값 * = 2;                 } else {                     // 이미 값이 설정되어있는 경우 유효한 이진 플래그 값인 경우에만 해당 값에서 계속 시작합니다.                     // 그렇지 않으면이 항목을 건너 뜁니다.                     if ($ key! = 0 && ($ key & ($ key - 1) == 0))                         $ 값 = 2 * $ 항목;                 }             }         } else {             // 일반 인덱스를 사용하려면 인덱스 0부터 시작합니다.             $ 값 = 0;             // 이제 모든 항목의 값을 설정할 수 있습니다.             foreach ($ items는 $ key => $ item) {                 if (! isset ($ item)) {                     // 값을 수동으로 설정하지 않으면 값을 설정하고 다음 항목의 값을 증가시켜야합니다.                     $ enum :: $$ key = $ value;                     $ value ++;                 } else {                     // 값이 이미 설정된 경우 해당 값에서 계속 처리합니다.                     $ 값 = $ item + 1;                 }             }         }     } }

  19. ==============================

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

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

    Notes : 나는 이것을 가지고 놀고 있었고, 방금 __call () 함수를 수정하여 실제 열거 형에 가깝게 접근 할 수 있다는 것을 깨달았다. __call () 함수는 알 수없는 모든 함수 호출을 처리합니다. 자, RED_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
    #           sim_sales@paypal.com.  :-)
    #
    #   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";
    
    ?>
    
  20. ==============================

    20.받아 들여진 대답은가는 길이고 실제로 단순함을 위해 무엇을하는지입니다. 열거 형의 대부분의 이점이 제공됩니다 (읽기 쉽고 빠름 등). 그러나 하나의 개념이 누락되었습니다. 대부분의 언어에서 허용되는 값을 제한하기 위해 열거 형을 사용합니다. 다음은 개인 생성자, 정적 인스턴스화 메서드 및 형식 확인을 사용하여 형식 안전성을 얻을 수있는 방법의 예입니다.

    받아 들여진 대답은가는 길이고 실제로 단순함을 위해 무엇을하는지입니다. 열거 형의 대부분의 이점이 제공됩니다 (읽기 쉽고 빠름 등). 그러나 하나의 개념이 누락되었습니다. 대부분의 언어에서 허용되는 값을 제한하기 위해 열거 형을 사용합니다. 다음은 개인 생성자, 정적 인스턴스화 메서드 및 형식 확인을 사용하여 형식 안전성을 얻을 수있는 방법의 예입니다.

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

    우리는 더 나아갈 수 있습니다. DaysOfWeek 클래스의 상수를 사용하면 오용이 발생할 수 있습니다. 사람이 실수로이 방법으로 사용할 수 있습니다.

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

    which is wrong (정수 상수를 호출). 우리는 상수 대신에 개인 정적 변수를 사용하여 이것을 막을 수 있습니다 :

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

    물론 정수 상수에 액세스 할 수 없습니다 (실제로 이것은 목적이었습니다). intVal 메서드를 사용하면 DaysOfWeek 객체를 정수 표현으로 변환 할 수 있습니다.

    enumeration이 광범위하게 사용되는 경우 메모리를 절약하기 위해 인스턴스화 메소드에 캐싱 메커니즘을 구현하여 더 나아갈 수도 있습니다.

    희망이 도움이 될 것입니다

  21. ==============================

    21.여기에 좋은 해결책이 있습니다!

    여기에 좋은 해결책이 있습니다!

    여기 내 버전입니다.

    나는 주요한 단점은 정적 멤버 선언 시간에 객체를 생성하는 PHP의 무능력과 설명 때문에 열거 형 멤버가 별도로 선언되고 인스턴스화되어야한다는 것입니다. 나는 이것이 파싱 된 문서 주석으로 반성을 대신 사용하는 방법 일 것이라고 생각한다.

    추상 열거 형은 다음과 같습니다.

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

    다음은 구체적인 enum 예제입니다.

    <?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, 'My second value');
            self::$MY_THIRD_VALUE = self::enum(3, 'My third value');
        }
    }
    
    EMyEnum::_init();
    

    다음과 같이 사용할 수 있습니다.

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

    그리고이 출력을 생성합니다 :

  22. ==============================

    22.

    class DayOfWeek {
        static $values = array(
            self::MONDAY,
            self::TUESDAY,
            // ...
        );
    
        const MONDAY  = 0;
        const TUESDAY = 1;
        // ...
    }
    
    $today = DayOfWeek::MONDAY;
    
    // If you want to check if a value is valid
    assert( in_array( $today, DayOfWeek::$values ) );
    

    리플렉션을 사용하지 마십시오. 따라서 코드를 추론하고 무언가가 사용되는 곳을 추적하는 것이 매우 어렵고 정적 분석 도구 (예 : IDE에 내장 된 기능)를 손상시키는 경향이 있습니다.

  23. ==============================

    23.@ Brian Cline의 답을 밟았습니다. 5 센트를 줄 수도 있다고 생각했습니다.

    @ Brian Cline의 답을 밟았습니다. 5 센트를 줄 수도 있다고 생각했습니다.

    <?php 
    /**
     * A class that simulates Enums behaviour
     * <code>
     * class Season extends Enum{
     *    const Spring  = 0;
     *    const Summer = 1;
     *    const Autumn = 2;
     *    const Winter = 3;
     * }
     * 
     * $currentSeason = new Season(Season::Spring);
     * $nextYearSeason = new Season(Season::Spring);
     * $winter = new Season(Season::Winter);
     * $whatever = new Season(-1);               // Throws InvalidArgumentException
     * echo $currentSeason.is(Season::Spring);   // True
     * echo $currentSeason.getName();            // 'Spring'
     * echo $currentSeason.is($nextYearSeason);  // True
     * echo $currentSeason.is(Season::Winter);   // False
     * echo $currentSeason.is(Season::Spring);   // True
     * echo $currentSeason.is($winter);          // False
     * </code>
     * 
     * Class Enum
     * 
     * PHP Version 5.5
     */
    abstract class Enum
    {
        /**
         * Will contain all the constants of every enum that gets created to 
         * avoid expensive ReflectionClass usage
         * @var array
         */
        private static $_constCacheArray = [];
        /**
         * The value that separates this instance from the rest of the same class
         * @var mixed
         */
        private $_value;
        /**
         * The label of the Enum instance. Will take the string name of the 
         * constant provided, used for logging and human readable messages
         * @var string
         */
        private $_name;
        /**
         * Creates an enum instance, while makes sure that the value given to the 
         * enum is a valid one
         * 
         * @param mixed $value The value of the current
         * 
         * @throws \InvalidArgumentException
         */
        public final function __construct($value)
        {
            $constants = self::_getConstants();
            if (count($constants) !== count(array_unique($constants))) {
                throw new \InvalidArgumentException('Enums cannot contain duplicate constant values');
            }
            if ($name = array_search($value, $constants)) {
                $this->_value = $value;
                $this->_name = $name;
            } else {
                throw new \InvalidArgumentException('Invalid enum value provided');
            }
        }
        /**
         * Returns the constant name of the current enum instance
         * 
         * @return string
         */
        public function getName()
        {
            return $this->_name;
        }
        /**
         * Returns the value of the current enum instance
         * 
         * @return mixed
         */
        public function getValue()
        {
            return $this->_value;
        }
        /**
         * Checks whether this enum instance matches with the provided one.
         * This function should be used to compare Enums at all times instead
         * of an identity comparison 
         * <code>
         * // Assuming EnumObject and EnumObject2 both extend the Enum class
         * // and constants with such values are defined
         * $var  = new EnumObject('test'); 
         * $var2 = new EnumObject('test');
         * $var3 = new EnumObject2('test');
         * $var4 = new EnumObject2('test2');
         * echo $var->is($var2);  // true
         * echo $var->is('test'); // true
         * echo $var->is($var3);  // false
         * echo $var3->is($var4); // false
         * </code>
         * 
         * @param mixed|Enum $enum The value we are comparing this enum object against
         *                         If the value is instance of the Enum class makes
         *                         sure they are instances of the same class as well, 
         *                         otherwise just ensures they have the same value
         * 
         * @return bool
         */
        public final function is($enum)
        {
            // If we are comparing enums, just make
            // sure they have the same toString value
            if (is_subclass_of($enum, __CLASS__)) {
                return get_class($this) === get_class($enum) 
                        && $this->getValue() === $enum->getValue();
            } else {
                // Otherwise assume $enum is the value we are comparing against
                // and do an exact comparison
                return $this->getValue() === $enum;   
            }
        }
    
        /**
         * Returns the constants that are set for the current Enum instance
         * 
         * @return array
         */
        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];
        }
    }
    
  24. ==============================

    24.좋아, 여기에 내 시도가 있습니다 강력하게 입력하고 매우 자연스럽게 사용하고 정의 할 수 있습니다.

    좋아, 여기에 내 시도가 있습니다 강력하게 입력하고 매우 자연스럽게 사용하고 정의 할 수 있습니다.

    정의:

    class Fruit extends Enum {
        static public $APPLE = 1;
        static public $ORANGE = 2;
    }
    Fruit::initialize(); //Can also be called in autoloader
    

    열거 형으로 전환

    $myFruit = Fruit::$APPLE;
    
    switch ($myFruit) {
        case Fruit::$APPLE  : echo "I like apples\n";  break;
        case Fruit::$ORANGE : echo "I hate oranges\n"; break;
    }
    
    >> I like apples
    

    열거 형을 매개 변수로 전달 (강력하게 형식화 됨)

    /** Function only accepts Fruit enums as input**/
    function echoFruit(Fruit $fruit) {
        echo $fruit->getName().": ".$fruit->getValue()."\n";
    }
    
    /** Call function with each Enum value that Fruit has */
    foreach (Fruit::getList() as $fruit) {
        echoFruit($fruit);
    }
    
    //Call function with Apple enum
    echoFruit(Fruit::$APPLE)
    
    //Will produce an error. This solution is strongly typed
    echoFruit(2);
    
    >> APPLE: 1
    >> ORANGE: 2
    >> APPLE: 1
    >> Argument 1 passed to echoFruit() must be an instance of Fruit, integer given
    

    에코 열거 형 문자열

    echo "I have an $myFruit\n";
    
    >> I have an APPLE
    

    정수로 열거 형 얻기

    $myFruit = Fruit::getByValue(2);
    
    echo "Now I have an $myFruit\n";
    
    >> Now I have an ORANGE
    

    이름으로 열거 형 얻기

    $myFruit = Fruit::getByName("APPLE");
    
    echo "But I definitely prefer an $myFruit\n\n";
    
    >> But I definitely prefer an APPLE
    

    열거 형 클래스 :

    /**
     * @author Torge Kummerow
     */
    class Enum {
    
        /**
         * Holds the values for each type of Enum
         */
        static private $list = array();
    
        /**
         * Initializes the enum values by replacing the number with an instance of itself
         * using reflection
         */
        static public function initialize() {
            $className = get_called_class();
            $class = new ReflectionClass($className);
            $staticProperties = $class->getStaticProperties();
    
            self::$list[$className] = array();
    
            foreach ($staticProperties as $propertyName => &$value) {
                if ($propertyName == 'list')
                    continue;
    
                $enum = new $className($propertyName, $value);
                $class->setStaticPropertyValue($propertyName, $enum);
                self::$list[$className][$propertyName] = $enum;
            } unset($value);
        }
    
    
        /**
         * Gets the enum for the given value
         *
         * @param integer $value
         * @throws Exception
         *
         * @return Enum
         */
        static public function getByValue($value) {
            $className = get_called_class();
            foreach (self::$list[$className] as $propertyName=>&$enum) {
                /* @var $enum Enum */
                if ($enum->value == $value)
                    return $enum;
            } unset($enum);
    
            throw new Exception("No such enum with value=$value of type ".get_called_class());
        }
    
        /**
         * Gets the enum for the given name
         *
         * @param string $name
         * @throws Exception
         *
         * @return Enum
         */
        static public function getByName($name) {
            $className = get_called_class();
            if (array_key_exists($name, static::$list[$className]))
                return self::$list[$className][$name];
    
            throw new Exception("No such enum ".get_called_class()."::\$$name");
        }
    
    
        /**
         * Returns the list of all enum variants
         * @return Array of Enum
         */
        static public function getList() {
            $className = get_called_class();
            return self::$list[$className];
        }
    
    
        private $name;
        private $value;
    
        public function __construct($name, $value) {
            $this->name = $name;
            $this->value = $value;
        }
    
        public function __toString() {
            return $this->name;
        }
    
        public function getValue() {
            return $this->value;
        }
    
        public function getName() {
            return $this->name;
        }
    
    }
    

    부가

    IDE에 코멘트를 추가 할 수도 있습니다.

    class Fruit extends Enum {
    
        /**
         * This comment is for autocomplete support in common IDEs
         * @var Fruit A yummy apple
         */
        static public $APPLE = 1;
    
        /**
         * This comment is for autocomplete support in common IDEs
         * @var Fruit A sour orange
         */
        static public $ORANGE = 2;
    }
    
    //This can also go to the autoloader if available.
    Fruit::initialize();
    
  25. ==============================

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

    이것은 "동적"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};
    
  26. ==============================

    26.어제 저는이 블로그를 제 블로그에 썼습니다. 나는 아마 PHP 스크립트에서 사용하기 쉽다고 생각한다.

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

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

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

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

    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 진술

  28. ==============================

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

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

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

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

    함수 매개 변수에 힌트를 입력 할 수 없습니다. 즉, 인스턴스화 할 수 없기 때문에뿐만 아니라 ShirtSize :: SMALL의 형식이 ShirtSize가 아닌 int이기 때문에 입력 할 수 없습니다.

    그렇기 때문에 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";
    

    이 방법은 사용자 관점에서 가장 큰 차이점은 상수의 이름에 a ()를 추가해야한다는 것입니다.

    한 가지 단점은 === (객체 평등을 비교) ==가 true를 반환하면 false를 반환한다는 것입니다. 이런 이유로 equals 메소드를 제공하는 것이 가장 좋습니다. 사용자는 두 개의 enum 값을 비교하기 위해 ==를 사용하지 않고 ===를 사용하는 것을 기억할 필요가 없습니다.

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

  29. ==============================

    29.브라이언 클라인 (Brian Cline)의 답변에 기반한 라이브러리를 만들었는데 greg0ire / enum 즐겨!

    브라이언 클라인 (Brian Cline)의 답변에 기반한 라이브러리를 만들었는데 greg0ire / enum 즐겨!

  30. ==============================

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

    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();
        }
    }
    
  31. from https://stackoverflow.com/questions/254514/php-and-enumerations by cc-by-sa and MIT license