带有内部值引用的序列化对象
Serialized object coming out with internal value references
这是迄今为止我在 PHP 中看到的最奇怪的事情,但肯定有某种解释。
使用 serialize()
我正在存储一些对象。稍后,我使用 unserialize()
.
恢复它们
今天我发现了一个未序列化的对象的问题。想象一下这个场景:
object__product_bundle Object (
[collateralValue] =>
[collateralGroup] =>
)
现在假设 $obj
是 object__product_bundle
的一个实例,如上所示。
当我这样做的时候:
$obj->collateralValue = 10;
并检查了对象变量,我被显示为:
object__product_bundle Object (
[collateralValue] => 10
[collateralGroup] => 10
)
令人难以置信!
我花了一个小时把头撞在 table 上,因为这没有意义。但是当我开始在对象上使用 var_dump()
时,在对其进行更改之前,我看到了这个:
object(object__product_bundle)#28 (15) {
["collateralValue"] => &NULL
["collateralGroup"] => &NULL
}
显然这些 properties/variables 之间存在某种联系。我研究了 &NULL
,发现的只有 this question,这告诉我我正在处理某种参考资料。
但是如何呢?
我的对象来自序列化字符串。
现在,看看我发现的序列化字符串:
s:15:"collateralValue";N;s:15:"collateralGroup";R:15;
什么是 R:15?
会不会是问题所在?
如何解决这个问题,问题从何而来?
编辑
深入挖掘后,我找到了罪魁祸首。
方位:
对象(如上所述)存储到另一个对象的 属性 中,该对象是购物车的项目。
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
}
显然,我对每个 object__product_*
使用 __sleep()
- return 那些变量名(包括 collateralValue
等等)。
现在的问题是:为什么 PHP 在处理休眠但同时结构发生变化的对象的新属性时创建引用?
非常混乱!
编辑#2
终于有了希望。
我的 __sleep()
函数基本上 return 编辑了一个硬编码的变量名数组,因为还有很多我不想存储在数据库中的其他变量名。这种方法显然导致了这个问题中描述的当前问题。
我仍然不知道为什么 PHP 在根本没有这些变量的情况下为唤醒的对象中的变量创建引用,但这些变量在 __sleep()
中被 return 编辑。
对我来说唯一明智的解决方案似乎是适应 __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()
将不会 return(这两个新的任何一个)变量名称(collateralValue、collateralGroup)在当前对象中未使用。
那么让我们分析一下你的序列化字符串:
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
这是迄今为止我在 PHP 中看到的最奇怪的事情,但肯定有某种解释。
使用 serialize()
我正在存储一些对象。稍后,我使用 unserialize()
.
今天我发现了一个未序列化的对象的问题。想象一下这个场景:
object__product_bundle Object (
[collateralValue] =>
[collateralGroup] =>
)
现在假设 $obj
是 object__product_bundle
的一个实例,如上所示。
当我这样做的时候:
$obj->collateralValue = 10;
并检查了对象变量,我被显示为:
object__product_bundle Object (
[collateralValue] => 10
[collateralGroup] => 10
)
令人难以置信!
我花了一个小时把头撞在 table 上,因为这没有意义。但是当我开始在对象上使用 var_dump()
时,在对其进行更改之前,我看到了这个:
object(object__product_bundle)#28 (15) {
["collateralValue"] => &NULL
["collateralGroup"] => &NULL
}
显然这些 properties/variables 之间存在某种联系。我研究了 &NULL
,发现的只有 this question,这告诉我我正在处理某种参考资料。
但是如何呢?
我的对象来自序列化字符串。
现在,看看我发现的序列化字符串:
s:15:"collateralValue";N;s:15:"collateralGroup";R:15;
什么是 R:15?
会不会是问题所在?
如何解决这个问题,问题从何而来?
编辑
深入挖掘后,我找到了罪魁祸首。
方位:
对象(如上所述)存储到另一个对象的 属性 中,该对象是购物车的项目。
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
}
显然,我对每个 object__product_*
使用 __sleep()
- return 那些变量名(包括 collateralValue
等等)。
现在的问题是:为什么 PHP 在处理休眠但同时结构发生变化的对象的新属性时创建引用?
非常混乱!
编辑#2
终于有了希望。
我的 __sleep()
函数基本上 return 编辑了一个硬编码的变量名数组,因为还有很多我不想存储在数据库中的其他变量名。这种方法显然导致了这个问题中描述的当前问题。
我仍然不知道为什么 PHP 在根本没有这些变量的情况下为唤醒的对象中的变量创建引用,但这些变量在 __sleep()
中被 return 编辑。
对我来说唯一明智的解决方案似乎是适应 __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()
将不会 return(这两个新的任何一个)变量名称(collateralValue、collateralGroup)在当前对象中未使用。
那么让我们分析一下你的序列化字符串:
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