Best way to create an empty object in JSON with PHP? - php

To create an empty JSON object I do usually use:
json_encode((object) null);
casting null to an object works, but is there any other preferable way and/or any problem with this solution?

Recommended method
json_decode ("{}") will return a stdClass per default, using the below should therefor be considered safe/portable and correct.
json_encode (new stdClass);
Your solution could work..
The documentation specifies that (object) null will result in an empty object, some might therefor say that your code is valid and that it's the method to use.
PHP: Objects - Manual
If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty.
.. but, try to keep it safe!
Though you never know when/if the above will change, so if you'd like to be 100% certain that you will always will end up with a {} in your encoded data you could use a hack such as:
$empty = json_decode ("{}");
$result = json_encode($empty); // "{}"
Even though it's tedious and ugly I do assume/hope that json_encode/json_decode is compatible with one another and always will evaluate the following to true:
$a = <something>;
$a === json_decode (json_encode ($a));

If you use objects as dynamic dictionaries (and I guess you do), then I think you want to use an ArrayObject.
It maps into JSON dictionary even when it's empty. It is great if you need to distinguish between lists (arrays) and dictionaries (associative arrays):
$complex = array('list' => array(), 'dict' => new ArrayObject());
print json_encode($complex); // -> {"list":[],"dict":{}}
You can also manipulate it seamlessly (as you would do with an associative array), and it will keep rendering properly into a dictionary:
$complex['dict']['a'] = 123;
print json_encode($complex); // -> {"list":[],"dict":{"a":123}}
unset($complex['dict']['a']);
print json_encode($complex); // -> {"list":[],"dict":{}}
If you need this to be 100% compatible both ways, you can also wrap json_decode so that it returns ArrayObjects instead of stdClass objects (you'll need to walk the result tree and recursively replace all the objects, which is a fairly easy task).
Gotchas. Only one I've found so far: is_array(new ArrayObject()) evaluates to false. You need to find and replace is_array occurrences with is_iterable.

Well, json_encode() simply returns a string from a PHP array/object/etc. You can achieve the same effect much more efficiently by doing:
$json = '{}';
There's really no point in using a function to accomplish this.
UPDATE
As per your comment updates, you could try:
$test = json_encode(array('some_properties'=>new stdClass));
Though I'm not sure that's any better than what you've been doing.

json_encode($array, JSON_FORCE_OBJECT) will do it too. see https://www.php.net/manual/en/function.json-encode.php

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.

Why does "scalar" appear like this when I cast json_decode() (in non-associative mode) to an object?

While doing some code refactoring I momentarily ended up in a situation where I was basically doing the (somewhat abstracted-out) equivalent of
$data = (object)json_decode('"test"');
Of course I understand json_decode() generates objects on its own unless assoc is false. (Incidentally I got into this situation because I was in the middle of moving some format processing code around, and I hadn't yet realized one of my (object) casts was now redundant.)
But... when this happened, PHP decided that $data contained:
stdClass Object
(
[scalar] => test
)
Wat.
scalar?!
Last I learned, "test" is a string, so it seems more than one pile of things has fallen over internally here. Or is this unintuitive yet intended design?!
I have of course removed the (object) and things work exactly how I intended now. So there's no bug here per se. I just wanted to understand what just happened.
Here you go, in case you want to join in the headscratching:
php -r 'print_r((object)json_decode("\"test\""));'
I'm using 7.0.25.
This is exactly what the manual specifies will happen when casting a scalar type (i.e. int, string, float, boolean) to an object.
If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty. An array converts to an object with properties named by keys and corresponding values. Note that in this case before PHP 7.2.0 numeric keys have been inaccessible unless iterated.
For any other value, a member variable named scalar will contain the value.
$obj = (object) 'ciao';
echo $obj->scalar; // outputs 'ciao'

Deleting all objects in the document array MongoDB PHP [duplicate]

To create an empty JSON object I do usually use:
json_encode((object) null);
casting null to an object works, but is there any other preferable way and/or any problem with this solution?
Recommended method
json_decode ("{}") will return a stdClass per default, using the below should therefor be considered safe/portable and correct.
json_encode (new stdClass);
Your solution could work..
The documentation specifies that (object) null will result in an empty object, some might therefor say that your code is valid and that it's the method to use.
PHP: Objects - Manual
If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty.
.. but, try to keep it safe!
Though you never know when/if the above will change, so if you'd like to be 100% certain that you will always will end up with a {} in your encoded data you could use a hack such as:
$empty = json_decode ("{}");
$result = json_encode($empty); // "{}"
Even though it's tedious and ugly I do assume/hope that json_encode/json_decode is compatible with one another and always will evaluate the following to true:
$a = <something>;
$a === json_decode (json_encode ($a));
If you use objects as dynamic dictionaries (and I guess you do), then I think you want to use an ArrayObject.
It maps into JSON dictionary even when it's empty. It is great if you need to distinguish between lists (arrays) and dictionaries (associative arrays):
$complex = array('list' => array(), 'dict' => new ArrayObject());
print json_encode($complex); // -> {"list":[],"dict":{}}
You can also manipulate it seamlessly (as you would do with an associative array), and it will keep rendering properly into a dictionary:
$complex['dict']['a'] = 123;
print json_encode($complex); // -> {"list":[],"dict":{"a":123}}
unset($complex['dict']['a']);
print json_encode($complex); // -> {"list":[],"dict":{}}
If you need this to be 100% compatible both ways, you can also wrap json_decode so that it returns ArrayObjects instead of stdClass objects (you'll need to walk the result tree and recursively replace all the objects, which is a fairly easy task).
Gotchas. Only one I've found so far: is_array(new ArrayObject()) evaluates to false. You need to find and replace is_array occurrences with is_iterable.
Well, json_encode() simply returns a string from a PHP array/object/etc. You can achieve the same effect much more efficiently by doing:
$json = '{}';
There's really no point in using a function to accomplish this.
UPDATE
As per your comment updates, you could try:
$test = json_encode(array('some_properties'=>new stdClass));
Though I'm not sure that's any better than what you've been doing.
json_encode($array, JSON_FORCE_OBJECT) will do it too. see https://www.php.net/manual/en/function.json-encode.php

php array or not array?

I don't understand... I'm doing something and when I do print_r($var); it tells me that I have an array, so naturally I think I have an array yet when I do
if(is_array($xml->searchResult->item))
it returns false
I use this array with foreach(); in documentation it says that foreach() won't work with anything else but array, so assuming that this is an array that I'm working...
plus, if I try to access it via
echo $xml->searchResult->item[3];
i will get 4th element of my array
print_r will also print objects as though they are arrays.
well, is_array() returns true if your variable is an array, otherwise, it returns false. In your case, $xml->searchResult->item seems not to be an array. What is the output for
var_dump($xml->searchResult->item)
? Another hint: You can determine the type of a variable via gettype().
is_array() returns true only for real php arrays. It is possible to create a "fake" array by using the ArrayAccess class. That is, you can use normal array semantics (such as item[3]) but it is not a real array. I suspect your $item is an object. So use
if($x instanceof ArrayAccess || is_array($x))
Instead.
plus, if I try to access it via echo $xml->searchResult->item[3]; i will get 4th element of my array
That's right, the first element is always 0 unless you specifically change it.
The manual does mention that foreach works on objects as well, and it will iterate over properties.
In your case, the situation is slightly different because I guess you're using SimpleXML, which is yet another special case. SimpleXMLElement has its own iterator, which I assume is hardcoded as it doesn't seem to implement any of SPL's Iterator interfaces.
Long story short, some objects can be used as an array, but they are not one.
Just be careful to check what has been returned by your array. You might have an object with class or stdClass which is empty and you cannot get element from it.

Problem with json_encode()

i have an simple array:
array
0 => string 'Kum' (length=3)
1 => string 'Kumpel' (length=6)
when I encode the array using json_encode(), i get following:
["Kum","Kumpel"]
My question is, what is the reason to get ["Kum","Kumpel"] instead of { "0" : "Kum", "1" : "Kumpel" }?
"{}" brackets specify an object and "[]" are used for arrays according to JSON specification. Arrays don't have enumeration, if you look at it from memory allocation perspective. It's just data followed by more data, objects from other hand have properties with names and the data is assigned to the properties, therefore to encode such object you must also pass the correct property names. But for array you don't need to specify the indexes, because they always will be 0..n, where n is the length of the array - 1, the only thing that matters is the order of data.
$array = array("a","b","c");
json_encode($array); // ["a","b","c"]
json_encode($array, JSON_FORCE_OBJECT); // {"0":"a", "1":"b","2":"c"}
The reason why JSON_FORCE_OBJECT foces it to use "0,1,2" is because to assign data to obeject you must assign it to a property, since no property names are given by developer (only the data) the encoder uses array indexes as property names, because those are the only names which would make sense.
Note: according to PHP manual the options parameters are only available from PHP 5.3.
For older PHP versions refer to chelmertz's answer for a way to make json_encode to use indexes.
As Gumbo said, on the JS-side it won't matter. To force PHP into it, try this:
$a = new stdClass();
$a->{0} = "Kum";
$a->{1} = "Kumpel";
echo json_encode($a);
Not that usable, I'd stick with the array notation.
Just cast as an object and it will work fine...the JSON_FORCE_OBJECT parameter does exactly the same thing.
json_encode((object)$array);
Don't forget to convert it back into a php array so you can access its values in php:
$array = (object)$array;
$array = (array)$array;
json_encode($array);
Since you’re having a PHP array with just numeric keys, there is no need to use a JavaScript object. But if you need one, try Maiku Mori’s suggestion.
I personally think this is a bug that needs to be fixed in PHP. JSON_FORCE_OBJECT is absolutely not an answer. If you try to do any sort of generic programming you get tripped up constantly. For example, the following is valid PHP:
array("0" => array(0,1,2,3), "1" => array(4,5,6,7));
And should be converted to
{"0": [0,1,2,3], "1": [4,5,6,7]}
Yet PHP expects me to either accept
[[0,1,2,3],[4,5,6,7]]
or
{"0":{"0":1,"1":1,"2":2,"3":3},"1":{"0":4,"1":5,"2":6,"3":7}}
Neither of which are right at all. How can I possibly decode an object like that? What possible reason is there to ever change something that is clearly using strings as indexes? It's like PHP was trying to be clever to help out idiotic people who can't differentiate strings from ints, but in the process messed up anyone legitimately using strings as indexes, regardless of what the value COULD be turned into.

Categories