PHP and Enumerations

后端 未结 30 1396
有刺的猬
有刺的猬 2020-11-22 13:39

I know that PHP doesn\'t have native Enumerations. But I have become accustomed to them from the Java world. I would love to use enums as a way to give predefined values whi

相关标签:
30条回答
  • 2020-11-22 14:00
    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>";
    }
    
    0 讨论(0)
  • 2020-11-22 14:00

    Finally, A PHP 7.1+ answer with constants that cannot be overridden.

    /**
     * An interface that groups HTTP Accept: header Media Types in one place.
     */
    interface MediaTypes
    {
        /**
        * Now, if you have to use these same constants with another class, you can
        * without creating funky inheritance / is-a relationships.
        * Also, this gets around the single inheritance limitation.
        */
    
        public const HTML = 'text/html';
        public const JSON = 'application/json';
        public const XML = 'application/xml';
        public const TEXT = 'text/plain';
    }
    
    /**
     * An generic request class.
     */
    abstract class Request
    {
        // Why not put the constants here?
        // 1) The logical reuse issue.
        // 2) Single Inheritance. 
        // 3) Overriding is possible.
    
        // Why put class constants here?
        // 1) The constant value will not be necessary in other class families.
    }
    
    /**
     * An incoming / server-side HTTP request class.
     */
    class HttpRequest extends Request implements MediaTypes
    {
        // This class can implement groups of constants as necessary.
    }
    

    If you are using namespaces, code completion should work.

    However, in doing this, you loose the ability to hide the constants within the class family (protected) or class alone (private). By definition, everything in an Interface is public.

    PHP Manual: Interfaces

    0 讨论(0)
  • 2020-11-22 14:01

    The accepted answer is the way to go and is actually what I am doing for simplicity. Most advantages of enumeration are offered (readable, fast, etc.). One concept is missing, however: type safety. In most languages, enumerations are also used to restrict allowed values. Below is an example of how type safety can also be obtained by using private constructors, static instantiation methods and type checking:

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

    We could even go further: using constants in the DaysOfWeek class might lead to misusage: e.g. one might mistakenly use it this way:

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

    which is wrong (calls integer constant). We can prevent this using private static variables instead of constants:

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

    Of course, it is not possible to access integer constants (this was actually the purpose). The intVal method allows to convert a DaysOfWeek object to its integer representation.

    Note that we could even go further by implementing a caching mechanism in instantiation methods to save memory in the case enumerations are extensively used...

    Hope this will help

    0 讨论(0)
  • 2020-11-22 14:02

    I used classes with constants:

    class Enum {
        const NAME       = 'aaaa';
        const SOME_VALUE = 'bbbb';
    }
    
    print Enum::NAME;
    
    0 讨论(0)
  • 2020-11-22 14:02

    I like enums from java too and for this reason I write my enums in this way, I think this is the most similiar behawior like in Java enums, of course, if some want to use more methods from java should write it here, or in abstract class but core idea is embedded in code below

    
    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
    
    
    0 讨论(0)
  • 2020-11-22 14:03

    What about class constants?

    <?php
    
    class YourClass
    {
        const SOME_CONSTANT = 1;
    
        public function echoConstant()
        {
            echo self::SOME_CONSTANT;
        }
    }
    
    echo YourClass::SOME_CONSTANT;
    
    $c = new YourClass;
    $c->echoConstant();
    
    0 讨论(0)
提交回复
热议问题