Malformed field names in Symfony JsonResponse - php

I have a strange problem with Symfony's JsonResponse that I cannot seem to figure out. I have the following action in my controller:
public function loadTemplateAction($id)
{
$repository = $this->getDoctrine()->getRepository('AppBundle:Host');
$template = $repository->find($id);
return new JsonResponse((array)$template);
}
It's supposed to find the given template in my repository by the passed id. I want to use the returned data in an ajax call. It does what I want, but it seems to "prefix" all the field names with an asterisk. So it returns a response like this:
I can't figure out why it's putting those asterisks in front of the field names (they are obviously not named that way in my datasource). Does anybody have a clue what could be causing this type of behaviour?

First of all, see http://php.net/manual/en/language.types.array.php:
If an object is converted to an array, the result is an array whose
elements are the object's properties. The keys are the member variable
names, with a few notable exceptions: integer properties are
unaccessible; private variables have the class name prepended to the
variable name; protected variables have a '*' prepended to the
variable name. These prepended values have null bytes on either side.
This can result in some unexpected behaviour:
You probably should not just typecast your object to arrays and JSON encode them. Have a look at some of the serialization solutions that exist:
http://symfony.com/doc/current/cookbook/serializer.html
http://jmsyst.com/libs/serializer
These libraries offer great control on how to serialize your objects to different formats, including JSON.
If you need less control on how your objects are serialized to JSON, you could just implement the JsonSerializable interface.

Related

Can a POST value ever be an instanceof something in PHP?

I've come across PHP code with the a check which tests if a POST value is an instanceof a class:
if ($_POST['something'] instanceof SomeClass) {
// do something
}
This seems odd to me, because I wouldn't think that the check can ever be true. A POST value is a string after all, and a string isn't an instance of a class.
I tried passing the serialized version of an instance (O:9:"SomeClass":0:{}), but that doesn't work (which makes sense, as it's still a string, not an object).
Am I correct in thinking that this check can never be true? Or am I missing something here?
I think this is not a simple question. I think theoretically "yes".
As a $_POST is a array of variables, and there is no limitation what the elements of a array can be, you can for example create a array of objects.
$array[] = new stdClass;
$array[0]->variable = value;
etc ...
You see the code author is checking if $_POST['something'], that is a element of the array, and that easily can be a object, is a instance of a class.
Now I have not tested it, but theoretically one could put a object of a class in a array and send it via $_POST nicely encoded.

Serialized object coming out with internal value references

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.
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 string
15 is the size of the string
collateralValue is the string itself the value (And if you look the string is 15 characters long)
First property (value):
N
N just mean NULL
Second property (key):
s:15:"collateralGroup"
s just means it is a string
15 is the size of the string
collateralGroup is the string itself the value (And if you look the string is 15 characters long)
Second property (value):
R:15
R means reference
15 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 property
For more information see: http://www.phpinternalsbook.com/classes_objects/serialization.html

How can I use a reference only and make no copies of the object argument in php

I have a function that requires information to be passed to it. The information is contained within an object. Therefore I must pass that object as one of the function arguments. The object is very large however, and I would like to reduce the overhead involved in making copies every time it is passed. Here is an example of
My function Call:
1 myFunction($myObject1);
and the function:
2 function myFunction($myObject2){
3 //do stuff
4 }
I understand there is more to it in php than just pass-by-reference vs pass-by-value. Correct me if I am wrong, but I believe on line 1 there is only a reference to the object made, but on line 2 the object is copied. To avoid this copy I have replaced ($myObject2) with (&$myObject2). I still refer to the object within the function definition as $myObject2 and everything seems to work. I believe I am now using a reference only and therefore making no copies of the object (which was my goal). Is my thinking correct? If not not why?
In PHP5, "objects" are not values. The value of the variables $myObject1, $myObject2 are object references (i.e. pointers to objects). You cannot get "the object itself"; objects can only be manipulated through these pointers.
Assignment and passing by value only copy values. Since objects are not values, they cannot ever be cloned through assignment, passing, etc. The only way to duplicate an object is to use the clone operator.
Putting & on a variable makes it pass or assign by reference, instead of by value without the &. Passing by reference allows you to modify the variable passed. Since the value of a variable cannot be an object, this has nothing to do with objects.

Unable to get object of array by index

EDITED:
I am generating a 2D array and storing it in db as json string. When I need to modify anything in the array, I then fetch the json string and decode it like
$myarray = (array)json_decode($jsonString);
The dump of array is as
$index = 2;
When I wan to access object at index '2' like $myarray[$index] I get null. Please guide what I am doing wrong?
In your comment you said this "array" was decoded from JSON. When you use json_decode, send true as the 2nd parameter. That tells it to make arrays instead of objects when decoding.
You're having trouble because the array is being decoded as an object, which you access using -> instead of [].
$newArray = json_decode($jsonString, true);
UPDATE: You were trying to do (array)json_decode($jsonString) and that wasn't working. That's because PHP is silly when it comes to type-casting.
Here's a quote from the PHP docs:
If an object is converted to an array, the result is an array whose
elements are the object's properties. The keys are the member variable
names, with a few notable exceptions: integer properties are
unaccessible; private variables have the class name prepended to the
variable name; protected variables have a '*' prepended to the
variable name. These prepended values have null bytes on either side.
This can result in some unexpected behaviour.
Source: http://php.net/manual/en/language.types.array.php#language.types.array.casting
So, it wasn't working because PHP said so.
try with
$index = '2';
I think you defined the array as associative.

PHP 5.3 SimpleXML to array type casting issue

I am trying to perform count on SimpleXML Element. It si giving me different results on PHP 5.3 and PHP 5.2. My code looks like follows :
$xml = new SimpleXMLElement('<command action="foo"/>');
print_r(count((array)$xml->children()));`
On PHP 5.2 the above prints "1" and on PHP 5.3 it prints "0" :(
I know I can use $xml->count but that does not take ino account the root element of the XML.
Just wondering what might be wrong in type casting the SimpleXML to array in PHP 5.3
Well, SimpleXMLElement::children() will always return a SimpleXMLElement instance according to the manual.
And it does according to var_dump.
But as command has no child, the returned object has no accessible attributes which yields to 0 when casting to array:
If an object is converted to an array, the result is an array whose
elements are the object's properties. The keys are the member variable
names, with a few notable exceptions: integer properties are
unaccessible; private variables have the class name prepended to the
variable name; protected variables have a '*' prepended to the
variable name. These prepended values have null bytes on either side.
Couldn't find anything about changed type casting to array for 5.2 to 5.3.
So this might (might) be a bug ...

Categories