对于PHP中enum的好奇

PHP中没有struct、enum这些东西,虽然万能的array用起来很爽,但写出来的代码typo问题很多、可维护性也差,需要更多的测试来辅助,而一旦加上测试的工作量是否还谈得上『爽』就是个问号了。

看了一篇研究Java enum机制的文章,文章里提到java的具体的enum其实就是一个类,重点是它的每一个枚举值也是一个enum对象。

对照着用PHP初步实现了一下。PHP的__callStatic 不支持静态属性访问,所以暂时用静态方法的形式访问枚举值 (string) Color::RED()。

<?php

interface enum
{
    
}

/**
 * @method enum RED() Description
 */
final class Color implements enum
{    
    private static $enums = 
        [
            'RED' => [255, 0, 0],
            'BLUE' => [0, 0, 255],
            'BLACK' => [0, 0, 0],
            'YELLOW' => [255, 255, 0],
            'GREEN' => [0, 255, 0]
        ];
    private static $objs = [];
    
    private $name;
    
    public static function __callStatic($name, $arguments)
    {
        if (!array_key_exists($name, static::$enums)) {
            throw new Exception('enum not existed', -1);
        }
        
        return static::valueOf($name);
    }
    
    private function setName($val): void
    {
        $this->name = $val;
    }
    
    private static function initEnum(string $name): bool
    {
        if (isset(static::$objs[$name])) {
            return true;
        }
        
        if (!array_key_exists($name, static::$enums)) {
            throw new Exception('enum not existed', -1);
        }
        
        $obj = new Color();
        $obj->setName($name);
        
        static::$objs[$name] = $obj;
        
        return true;
    }
    
    public static function values(): array
    {
        if (empty(static::$objs)) {
            foreach (array_keys(static::$enums) as $name) {
                static::initEnum($name);
            }
        }
        
        return static::$objs;
    }
    
    public static function valueOf(string $name): enum
    {
        if (!array_key_exists($name, static::$enums)) {
            throw new Exception('enum not existed', -1);
        }
        
        static::initEnum($name);
        
        return static::$objs[$name];
    }
    
    public function ordinal(): int
    {
        //TODO
        return 0;
    }
    
    /**
     * @throws ClassCastException
     */
    public function compareTo(enum $other): int
    {
        //TODO
        return -1;
    }
    
    public function equals(enum $other): bool
    {
        //TODO
        return true;
    }
    
    public function __toString()
    {
        if (!$this->name) {
            return '';
        }
        
        return '(' . implode(',', static::$enums[$this->name]) . ')';
    }
}  


echo (string) Color::RED();
echo (string) Color::valueOf('BLACK');

代码并没有做细致的抽象,如果要进一步抽象的话,可以试试定义一个EnumTraits来包含那些公共方法。

会不会有人问,既然你这么喜欢Java的enum,为什么不直接用Java得了。

posted @ 2017-04-14 09:34  x3d  阅读(7028)  评论(0编辑  收藏  举报