Использование отражения PHP для построения перечисления - PullRequest
1 голос
/ 14 декабря 2011

Я пытался найти метод для обработки перечисления в 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* } }

Значение (new $class), входящее в setStaticPropertyValue, является правильным, и создается только три из них.

getStaticProperties собирает только статические свойства (как и должно быть), и единственное место, которое назначается private $_value, находится в конструкторе. Для полноты, конструктор вызывается только три раза, и внутри конструктора значение, как и ожидалось, только когда-либо 1, 2 или 3. Короче говоря, все выглядит идеально, пока не вызовет setStaticPropertyValue.

Я не могу понять, что здесь происходит. Где и почему private $_value присвоено это неправильное значение? Я неправильно использую отражение? Что создает эти бесконечные рекурсивные объекты?

1 Ответ

1 голос
/ 14 декабря 2011

Это увлекательно. Мне нравится, когда я сталкиваюсь с вещами, которые раздвигают границы PHP.

Я должен сказать, однако, что это кажется немного экстремальным, и в зависимости от того, насколько быстро отражение, оно может быть довольно медленным.

Для фреймворка, который я написал, я создал простую функцию enum . Все, что он делает, это автоматизирует определения. Мне больше нравится ваш подход, потому что вы можете ограничить ввод текста.

Ваш код работает на меня. Я публикую свои правки ниже - в основном это изменения форматирования, чтобы мне было удобнее их читать.

Посмотри, что я с ним сделал. Я протестировал это с 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
...