我正在编写一个类似于Java Currency的PHP类:
该类的设计使得任何给定货币永远不会有多个Currency实例。因此,没有公共构造函数。您可以使用getInstance方法获取Currency实例。
使用PHP保存实例化对象的静态数组,并在getInstance()
中执行查找以返回现有实例,或者在需要时实例化它是相当容易的。
问题来自序列化。即使我实现了Serializable,我也无法在unserialize()
中选择我想要返回的实例,因为此时对象已经被实例化了,因为在PHP中你不能覆盖{{1} }:
$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));
构建一个类似的对象,但我想知道是否有可能获得相同的对象。
答案 0 :(得分:1)
td; dr; 不,你不能在PHP中本地执行此操作,因为unserialize()
不支持与Java相同的readResolve()
功能。
在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))));
当然,没有什么可以阻止某人不要调用Currency::resolve()
,然后你会得到多个给定货币代码的对象。