使用PHP反射构建枚举


Using PHP reflection to build enumeration

我试图找到一种在PHP中处理枚举的方法。我找到的所有方法都不能真正使用枚举来限制函数/方法的参数,这是我想要枚举的主要原因。

所以我开始尝试创建我自己的,但现在遇到了一个问题,使用反射:

<?php
class Enum {
    private $_value;
    protected function __construct($value) {
        $this->_value = $value;
    }
    public function getValue() {
        return $this->_value;
    }
    protected static function enumerate($class) {
        $ref = new ReflectionClass($class);
        $instances = array();
        foreach ($ref->getStaticProperties() as $name => $value) {
            $ref->setStaticPropertyValue($name, new $class($value));
        }
    }
}
class Book extends Enum {
    public static $COMIC = 1;
    public static $NOVEL = 2;
    public static $EDUCATIONAL = 3;
    public static function enumerate() {
        parent::enumerate(__CLASS__);
    }
}
Book::enumerate();
function read(Book $book) {
    echo '<hr/>';
    var_dump($book);
}
read(Book::$COMIC);
read(Book::$EDUCATIONAL);
?>

我希望输出显示两个Book对象及其各自的值,但我得到了这样的结果:

object(Book)#2 (1) { ["_value:private"]=> object(Book)#2 (1) { ["_value:private"]=> *RECURSION* } }
object(Book)#4 (1) { ["_value:private"]=> object(Book)#4 (1) { ["_value:private"]=> *RECURSION* } }

进入setStaticPropertyValue的值(new $class)是正确的,并且只创建了三个。

getStaticProperties只拾取静态属性(因为它应该),private $_value被分配的唯一地方是在构造函数中。为了完整起见,构造函数只被调用三次,并且在构造函数内部,值如预期的那样只有1、2或3。简而言之,一切似乎都很好,直到调用setStaticPropertyValue

我不知道这里发生了什么事。在哪里,为什么是private $_value分配这个错误的值?我是不是用错了反射?是什么创造了这些无限递归对象?

这很有趣。当我遇到突破PHP边界的东西时,我喜欢它。

我不得不说,这似乎有点极端,这取决于反射有多快,它可能相当慢。

对于我编写的框架,我创建了一个简单的枚举函数。它所做的就是自动化定义。我更喜欢你的方法,因为你可以进行类型限制。

你的代码为我工作。我把我的编辑贴在下面——它们主要是格式的改变,这样我可以更容易地阅读。

看看我对它做了什么。我在5.3.5和5.2.17上测试了这个-在任何一个上都可以正常工作。

<?php
header( 'content-type: text/plain' );
Book::enumerate();
Book::$COMIC->read();
read(Book::$EDUCATIONAL);
read(Book::$NOVEL );
class Enum
{
    private $_value;
    protected function __construct($value)
    {
        $this->_value = $value;
    }
    public function getValue()
    {
        return $this->_value;
    }
    protected static function enumerate($class)
    {
        $ref = new ReflectionClass($class);
        $instances = array();
        foreach ( $ref->getStaticProperties() as $name => $value )
        {
            $ref->setStaticPropertyValue( $name, new $class( $value ) );
        }
    }
}
class Book extends Enum
{
    public static $COMIC = 'comic';
    public static $NOVEL = 'novel';
    public static $EDUCATIONAL = 'edu';
    public static function enumerate()
    {
        parent::enumerate(__CLASS__);
    }
    public function read()
    {
        echo "'nReading a {$this->getValue()} book'n";
    }
}
function read( Book $book )
{
    echo "'nReading a {$book->getValue()} book'n";
}

Reading a comic book
Reading a edu book
Reading a novel book