【问题标题】:Is it possible serialize SplEnum in php是否可以在 php 中序列化 SplEnum
【发布时间】:2014-08-04 15:57:11
【问题描述】:

是否可以序列化 SplEnum?我正在尝试使用 SplEnum,但用户化实例只有默认值。 例如:

class Test extends SplEnum
{
    const __default = self::A;
    const A = 1;
    const B = 2;
}

...

$t = new Test( Test::B );
$s = serialize($t);
$t2 = unserialize($s);

变量 $t2 是 Test 的实例,但具有默认值。

【问题讨论】:

    标签: php spl


    【解决方案1】:

    反序列化后没有得到预期值的原因是SplEnum 不仅仅是一个普通的PHP 类。这是一种黑客行为。该值保存在其自己的结构中,而不是您可以在此处看到的 PHP 对象本身中

    https://github.com/davidcoallier/SPL_Types/blob/master/spl_type.c 在方法 spl_type_object_new_ex

    他们创建了一个内部结构“对象”

    object = emalloc(sizeof(spl_type_object));
    

    持有价值

    ZVAL_ZVAL(object->value, *def, 1, 0);
    

    unserialize 函数对这个内部对象一无所知,也不能改变它的值。因此出现了这种特殊的行为。

    更新

    您可能希望使用强制转换来保留对象的值。在您的情况下,它可能是:

    $casted_value = (int) $t;
    

    至少一个整数更容易处理。

    更新 2

    一个工作序列化的工作示例。

    class Test2 extends SplEnum  implements Serializable 
    {
        const __default = 1;
        const A = 1;
        const B = 27;
        const C = 31;
    
        public function serialize() {
                return serialize ((int) $this);
        }
    
        public function unserialize($serialized) {
            $this->__construct (unserialize($serialized));
        }
    }
    

    【讨论】:

    • PHP 知道它的 ZVALs ;-) 这个解释对我来说似乎不正确,因为默认情况下你不能序列化/反序列化任何 const 并且你不能重新声明一个常量。
    • 有 __default 属性保存该值。 "O:4:"Test":1:{s:9:"__default";i:2;}"
    • __default 是常量,不是属性
    • 如果这是一个常量,它是如何在序列化字符串中结束的?
    • 我猜是SplType::__construct ([ mixed $initial_value [, bool $strict ]] ) 生成了一些带有值的private 属性。我无法重现,因为我没有SplEnum,如果我尝试使用带有常量的对象serialize,这些常量不会打印在序列化字符串中。我们可以使用反射类进一步研究这一点,看看什么是可见以及可以做什么。但是很确定 constdeclared 对象变量不能被反序列化,因为它是 const。
    【解决方案2】:

    这不是特定于 SPL 的,您根本无法序列化常量,因为它们不是对象的属性。

    如果您实现__wake() 方法,则可以序列化任何常量实现Serializable 接口,如下面的代码所示。

    http://de2.php.net/manual/en/language.oop5.magic.php#object.sleep

    <?php
    class Test extends SplEnum implements Serializable {
        const A = 1;
    
        public function serialize() {
            return serialize(array('A' => self::A));
        }
    
        public function unserialize($serialized) {
            // cannot redeclare A when unserializing!
            // This is not SplEnum specific but with every class.
        }
    }
    
    $test = new Test;
    
    echo serialize($test);
    

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      • 2012-11-12
      相关资源
      最近更新 更多