Reputation: 5840
This is by far the strangest thing i have seen in PHP, but there surely is some sort of explanation.
Using serialize()
i am storing some objects. At a later point, i revive them using unserialize()
.
Today i discovered a problem with an object that has been unserialized. Picture this scenario:
object__product_bundle Object (
[collateralValue] =>
[collateralGroup] =>
)
Now imagine $obj
to be an instance of object__product_bundle
as shown above.
When i did:
$obj->collateralValue = 10;
And checked the object variables, i was shown:
object__product_bundle Object (
[collateralValue] => 10
[collateralGroup] => 10
)
Mindboggling!
I spent an hour smashing my head against the table, as this didn't make sense. But when i started using var_dump()
on the object, before making changes to it, i saw this:
object(object__product_bundle)#28 (15) {
["collateralValue"] => &NULL
["collateralGroup"] => &NULL
}
Apparently these properties/variables were somehow linked. I researched &NULL
and all i found was this question which told me i am dealing with some sort of references.
But how?
My object comes from a serialized string.
Now, taking a look at the serialized string i found this:
s:15:"collateralValue";N;s:15:"collateralGroup";R:15;
What is R:15 ?
Can it be the issue?
How can this problem be addressed and where does it come from?
EDIT
After digging deeper, i found the culprit.
Orientiation:
The objects (as described above) are stored into a property of another object, which is the item of a shop cart.
class shopCart {
public $storage;
}
$cart->storage[] = new shopCart_item();
class shopCart_item {
public $object;
}
$object
is where the products (object__product_*
) are stored.
Upon placing an order, with the aim of being repeated (subscription), this entire shopCart
is stored into the database as a blob.
Whenever a subscription order is scheduled, an automated task then grabs the old shopCart
and generates a new order from it.
And here i found the culprit - i added the properties (collateralValue
etc.) later during development, but there had already been stored orders.
Now during debugging i found that this is where PHP starts creating references, although i do not understand why.
Simply put:
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, i use __sleep()
for each object__product_*
- which returns those variable names (including collateralValue
and so on).
The question now becomes then: Why does PHP create references, when it is dealing with new properties for objects that were asleep but whose structure has changed in the meantime?
Very confusing!
EDIT #2
Finally some hope.
My __sleep()
function basically returned a hardcoded array of variable names, as there were a ton of others i never wanted to store in the database. This approach apparently led to the current problem described in this question.
I still do not know why PHP creates references for variables in objects that were awoken without having those variables at all, but with those variables being returned in __sleep()
.
The only sensible solution to me, seemed to be to adapt __sleep()
. I now do this:
public function __sleep(){
$vars=array(
'dbId',
'title',
'articleId',
'price_per_unit',
);
if(isset($this->collateralValue))
$vars[]='collateralValue';
if(isset($this->collateralGroup))
$vars[]='collateralGroup';
}
This way, __sleep()
will not return (any of those two new) variable names (collateralValue, collateralGroup) which are not in use in the current object.
Upvotes: 2
Views: 67
Reputation: 59701
Well let's analyse your serialized string:
s:15:"collateralValue";N;s:15:"collateralGroup";R:15;
First property (key):
s:15:"collateralValue"
s
just means it is a string15
is the size of the stringcollateralValue
is the string itself the value (And if you look the string is 15 characters long)First property (value):
N
N
just mean NULLSecond property (key):
s:15:"collateralGroup"
s
just means it is a string15
is the size of the stringcollateralGroup
is the string itself the value (And if you look the string is 15 characters long)Second property (value):
R:15
R
means reference15
means to the 15 value. So here the 15 value is probably the property collateralValue
, which means if you change the value of it it also changes the value of the collateralGroup
propertyFor more information see: http://www.phpinternalsbook.com/classes_objects/serialization.html
Upvotes: 1