1

我正在编写一个类似于 Java 的Currency的 PHP 类:

该类的设计使得任何给定货币的 Currency 实例都不会超过一个。因此,没有公共构造函数。您可以使用 getInstance 方法获取 Currency 实例。

使用 PHP 保留实例化对象的静态数组并执行查找getInstance()以返回现有实例或在需要时实例化它是相当容易的。

问题来自序列化。即使我实现了Serializable,我也无法选择要返回的实例unserialize(),因为此时对象已经实例化,并且因为在 PHP 中您无法覆盖$this

class Currency implements Serializable
{
    public function getInstance()
    {
        // ...
    }

    public function serialize()
    {
        // ...
    }

    public function unserialize($data)
    {
        // At this point, the object is already instantiated,
        // so I can't just return self::getInstance(),
        // and can't override $this
    }
}

是否有任何技术解决方案可以选择在反序列化时返回的实例?

- 编辑 -

这是我要解决的用例:

$euro = Currency::getInstance('EUR');
assert($euro === unserialize(serialize($euro));

我知道我可以用 构建一个类似的对象unserialize(),但我想知道是否有可能获得相同的对象。

4

1 回答 1

1

td;博士; 不,您不能在 PHP 中本地执行此操作,因为unserialize()它不支持与readResolve()Java 相同的功能。

在 Java 中,在反序列化时,会创建对象的新实例,恢复其状态,然后readResolve()在类上调用(如果存在)。readResolve()获取新创建的反序列化对象,然后将其解析为另一个对象(如果需要),此时解析的对象就是反序列化返回的对象。readResolve()如果返回的对象与提供给它的对象不同,则最初创建的新实例将被垃圾回收。

在 PHP 中,在unserialize(). 您可以实现一个解决方法,但是,定义您自己的解析方法来模拟readResolve(),但您需要在unserialize().

class Currency implements Serializable {
    private $currencyCode;
    private static $instances = array();

    private function __construct( $currencyCode) {
        $this->currencyCode = $currencyCode;
    }

    public static function getInstance( $currencyCode) {
        if( !isset( self::$instances[$currencyCode])) {
            self::$instances[$currencyCode] = new Currency( $currencyCode);
        }
        return self::$instances[$currencyCode];
    }

    public function serialize() {
        return serialize( $this->currencyCode);
    }

    public function unserialize( $data) {
        $this->currencyCode = unserialize( $data);
    }

    public static function resolve( $obj) {
        $new = self::getInstance( $obj->currencyCode);
        if( $new !== $obj) {
            unset( $obj);
        }
        return $new;
    }
}

$euro = Currency::getInstance('EUR');
assert($euro === Currency::resolve( unserialize(serialize($euro))));

Of course, there is nothing stopping somebody from not calling Currency::resolve(), and you will then end up with more than one object for the given currency code.

于 2013-04-09T18:01:34.687 回答