这是我在PHP中看到的最奇怪的东西,但肯定有某种解释。
使用serialize()
我正在存储一些对象。稍后,我使用unserialize()
恢复它们。
今天我发现了一个已被反序列化的对象的问题。想象一下这种情况:
object__product_bundle Object (
[collateralValue] =>
[collateralGroup] =>
)
现在假设$obj
是object__product_bundle
的一个实例,如上所示。
当我做的时候:
$obj->collateralValue = 10;
并检查了对象变量,我看到了:
object__product_bundle Object (
[collateralValue] => 10
[collateralGroup] => 10
)
Mindboggling!
我花了一个小时把头撞在桌子上,因为这没有意义。但是当我开始在对象上使用var_dump()
时,在对其进行更改之前,我看到了这一点:
object(object__product_bundle)#28 (15) {
["collateralValue"] => &NULL
["collateralGroup"] => &NULL
}
显然这些属性/变量以某种方式相关联。我研究了&NULL
,我找到的只是this question,它告诉我我正在处理某种参考文献。
但是怎么样?
我的对象来自序列化字符串。
现在,看一下我发现的序列化字符串:
s:15:"collateralValue";N;s:15:"collateralGroup";R:15;
什么是R:15?
这可能是问题吗?
如何解决这个问题以及它来自哪里?
修改
深入挖掘后,我找到了罪魁祸首。
Orientiation:
对象(如上所述)存储在另一个对象的属性中,该对象是商店购物车的项目。
class shopCart {
public $storage;
}
$cart->storage[] = new shopCart_item();
class shopCart_item {
public $object;
}
$object
是存储产品(object__product_*
)的地方。
下订单时,为了重复(订阅),整个shopCart
将作为blob存储到数据库中。
每当订阅订阅订单时,自动化任务就会抓取旧版shopCart
并从中生成新订单。
在这里我找到了罪魁祸首 - 我在开发过程中稍后添加了属性(collateralValue
等),但是已经存储了订单。
现在在调试期间我发现这是PHP开始创建引用的地方,虽然我不明白为什么。
简单地说:
static public function generateOrderFromSubscription() {
[...]
$order = new object__webShop_order();
var_dump($subscription->cart); // <-- no references are in here at all
$order->cart = serialize($subscription->cart);
var_dump($order->cart); // <-- suddenly, here i have the references
}
Apparantely,我为每个__sleep()
使用object__product_*
- 它返回这些变量名称(包括collateralValue
等等)。
现在的问题是:为什么PHP在处理睡眠对象的新属性时会创建引用,但同时其结构已发生变化?
非常混乱!
编辑#2
最后有些希望。
我的__sleep()
函数基本上返回了一个硬编码的变量名称数组,因为还有很多其他我从未希望存储在数据库中的函数。这种方法显然导致了这个问题中描述的当前问题。
我仍然不知道为什么PHP会为没有这些变量而被唤醒的对象中的变量创建引用,但这些变量在__sleep()
中返回。
对我来说唯一明智的解决方案似乎是要适应__sleep()
。我现在这样做:
public function __sleep(){
$vars=array(
'dbId',
'title',
'articleId',
'price_per_unit',
);
if(isset($this->collateralValue))
$vars[]='collateralValue';
if(isset($this->collateralGroup))
$vars[]='collateralGroup';
}
这样,__sleep()
将不会返回(这两个新的)变量名称(collateralValue,collateralGroup),这些名称在当前对象中没有使用。
答案 0 :(得分:1)
让我们分析你的序列化字符串:
s:15:"collateralValue";N;s:15:"collateralGroup";R:15;
第一个属性(关键):
s:15:"collateralValue"
s
只是意味着它是一个字符串15
是字符串的大小collateralValue
是字符串本身的值(如果你看字符串是15个字符长)第一个属性(值):
N
N
只是意味着NULL 第二个属性(关键):
s:15:"collateralGroup"
s
只是意味着它是一个字符串15
是字符串的大小collateralGroup
是字符串本身的值(如果你看字符串是15个字符长)第二个属性(值):
R:15
R
表示参考15
表示15值。所以这里的15值可能是属性collateralValue
,这意味着如果更改它的值,它也会更改collateralGroup
属性的值有关详细信息,请参阅:http://www.phpinternalsbook.com/classes_objects/serialization.html