Empty array in PHP -> JSON -> JS = empty array in Javascript. How to get empty Object instead? - php

So here is the basis for building my JSON response back to my JS.
$this->_response['vendor'] = array();
foreach ($_results as $_row) {
$this->_response['vendor'][$_row['id']] = $_row;
}
echo(json_encode($this->_response));
This is fine and builds objects in javascript fine, unless there were no results. In that case, the php sees it as an empty numeric array, instead of an associative array. This then comes down to javascript and converts to an empty array instead of an empty object.
I know I can fix this in a number of ways by checking things, pre-declaring the variables as objects in javascript etc. What I'm wondering is if there is a way to declare an empty associative array in php, or some other way to force json_encode to create an object ("{}") instead.

It's a known limitation of PHP - since it doesn't support JavaScript types natively (eg. objects), decoding and then encoding again may lead to data loss.
I use a workaround like this to keep JSON in tact:
/**
* #param $input
* #return array
*/
public static function safeDecode($input) {
// Fix for PHP's issue with empty objects
$input = preg_replace('/{\s*}/', "{\"EMPTY_OBJECT\":true}", $input);
return json_decode($input, true);
}
/**
* #param array|object $input
* #return string
*/
public static function safeEncode($input) {
return preg_replace('/{"EMPTY_OBJECT"\s*:\s*true}/', '{}', json_encode($input));
}
It's not ideal but it works. Note that you can:
json_decode() to objects, which is default manner. Then empty objects are not lost, but most modern frameworks REQUIRE arrays because most collection manipulation tools work with arrays. Therefore, in most cases it's not a viable option;
You could force json_encode() to encode empty arrays to objects but then you will lose empty arrays - not a nice option either.
Therefore, a work around like mine shown above is perhaps the only option at this moment. In short, you have to extend PHPs json_encode() and json_decode(). Unfortunately PHP doesn't allow built-in function overloading so you have to define functions with different names.

I suppose the most reasonable answer here is that there's probably no point in delivering an empty array or object in the first place. Simple checks for existence in the javascript would then handle the problem.
if (count($_results)) {
$this->_response['vendor'] = array();
foreach ($_results as $_row) {
$this->_response['vendor'][$_row['id']] = $_row;
}
}
echo(json_encode($this->_response));

Related

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

How to force int to string in Laravel JSON?

I've recently updated my server to a newer version of MySQL and PHP 7 for various reasons. On my previous instance, running PHP 5.5, Laravel's response()->json() always converted tinyint's into a string. Now running newer server software, it's returning me int's -as it should...
I'd have to change a lots of my codebase to either cast types / convert them into a string manually, whic I'm trying to avoid at the moment.
Is there a way to somehow force response()->json() to return int's as string's?
Is there a way to somehow force response()->json() to return int's as string's
I don't want to change the code base - do not want to cast types, convert it,
No. There's no option for that. You need to do that yourself if needed.
There is a way to cast integer into string in laravel
in your model you can cast id to string. Its as follows
protected $casts = [ 'id' => 'string' ];
But the downside is that you would have to do that for all Models.
If you don't want to modify a lot of code you could run response data through a quick and dirty function. Instead of going directory to JSON you should instead grab the data as a nested array. Then put it through a function like this:
function convertIntToString ($myArray) {
foreach ($myArray as $thisKey => $thisValue) {
if (is_array($thisValue)) {
// recurse to handle a nested array
$myArray[$thisKey] = convertIntToString($thisValue);
} elseif (is_integer($thisValue)) {
// convert any integers to a string
$myArray[$thisKey] = (string) $thisValue;
}
}
return $myArray;
}
The function will convert integers to strings and use recursion to handle nested arrays. Take the output from that and then convert it to JSON.
The best solution for me is to to use attribute casting and
Fractal transformers
Fractal transformers are extremely useful when you have complex responses with multiple relations included.
You can typecast it to string:
return response->json(["data" => (string)1]);

PHP inline access to Array elements returned by an Object Method

Say we have the object $teams (an associative array) containing an object that provides the method getMembers() which returns an Array as follows:
$membersArray = $teams['blueteam']->getMembers();
If I want to then access individual members, I may do so as follows:
$membersArray[1];
Why can't I perform the access in-line as follows, and is there a proper way to do so in PHP?
$membersArray = $teams['blueteam']->getMembers()[1];
Support for this added in PHP 5.4.0:
$membersArray = $teams['blueteam']->getMembers()[1];
Rather than try to access it like that, why not make an alternative method called getMember() which accepts a parameter for the array index. For example:
function getMember( $index )
{
return $this->members[$index];
}
This makes your code a little more self-documenting by indicating getMembers will return an array of members, where getMember() will only return a single array element.

php - multi-dimensional array wrapper class

I have some data represented as multi-dimensional arrays. I would like to embed these data into my OO application and provide extra functionality to these data but also a way to access it both with the traditional random access and using an iterator (so I could use foreach). In other words I would like to implement a wrapping class for a multi-dimensional array.
What I already tried:
I. ArrayAccess
The problem with this one is that the server uses PHP 5.2.17 and &offsetGet() gives an error, thus I can't return by reference, which means I can't implement multidimensional element access:
$obj[$key1][$key2] = $value;
Note, that upgrading to a newer PHP version is currently not an option
II. Using magic methods
This is a bit trickier, but my problems rose when I tried using a variable as key. E.g.
$obj->$key1[$key2] = $value;
The interpreter first evaluated $key1[$key2] throwing a notice and returning the first char of $key1, and uses that as key on my array. I don't know how to solve this one either. I thought of using brackets to force operation priority, but that had the same problem as in my next attempt:
III. Using simple get and set functions
Again, old PHP. It cries when I try to write:
$obj->get($key1)[$key2] = $value;
Because it doesn't know how to index an expression ending in round brackets.
There's still the lost resort option: make the array public and forget OO all together. But before I go there I want to be certain that there's just really no other way of doing this.
Sometimes, it's best shown with an example. For instance, you could have a multidimensional array with ordered quantities of a product, where the first index defines a customer, the second an order and the third the products. The value then is the quantity.
IV. Using simple get and set functions, but with multiple parameters:
$value = $obj->get($key1, $key2);
$obj->set($key1, $key2, $value);
or
$quantity = $orderedQuantities($customerName, $orderNo, $productCode);
The essence of writing an object wrapper, is that it looks like an object and behaves like such. If you implement it so that it looks and behaves like an array, you may just as well use an array. The only reason to wrap an array in an object that behaves like an array is that you can pass it around by reference, without using & parameters.
If that is your goal, just assign the array to $obj, and use $obj->arrayprop[$key1][$key2]. If on the other hand you want it to behave like an object, skip the array syntax altogether.
V. Using nested objects
So using the same example, you can write a customers object (kind of a collection), which embeds order objects, etc..
$quantity = $customers->getCustomerByName($customerName)->getOrder($orderNo)->getProduct($productCode)->quantity;
or, to make it more readable:
$customer = $customers->getCustomerByName($customerName);
$order = $customer->getOrder($orderNo);
$orderLine= $order->getOrderLine($productCode);
$quantity = $product->quantity;
Now, each of these entities are represented by an object. The advantage is that you can easily extend this structure with extra properties. You can give the customer collection 'findByCustomerNo' and 'findByName' methods to find a specific customer, but also a 'filterByPostalCode', which could return a new collection containing only the customers from that postal code.
$order could now contain functions to calculate totals.
$orderLine may contain only a productCode (key) and a quantity, but by making it an object, you can easily add discount, a customized name or description or other properties.
All in all, this structure allows a lot of flexibility, although it needs a little more typing at first and a little getting used to.
Using nested objects can make ArrayAccess work, without passing references. But you can forget about built in array functions completely.
<?php
class ArrObj implements ArrayAccess {
private $arr;
public function __construct($arr = null) {
$this->arr = $arr;
}
public function offsetExists($key) {
return isset($this->arr[$key]);
}
public function offsetGet($key) {
return $this->arr[$key];
}
public function offsetSet($key, $val) {
return $this->arr[$key] = $val;
}
public function offsetUnset($key) {
unset($this->arr[$key]);
}
}
$a = new ArrObj(array(
'foo' => new ArrObj(array(
'bar' => 'qwe'
))
));
echo $a['foo']['bar'] . '<br />';
$a['foo']['bar'] = 'asd';
echo $a['foo']['bar'] . '<br />';
?>
Outputs:
qwe
asd

Is there a version of the PHP array that is pass-by-reference?

I'm asking this because I'm working with a recursive function that generates a large array tree and the pass-by-copy aspect of the arrays are completely screwing with my head. I've tried using ArrayObject, but that's really an object, isn't it? None of the array_keys type array functions work with it, and json_encode doesn't understand that it's an array.
I'd like a version of the PHP array that feels, smells and looks like the normal array, but is pass-by-reference. Is there anything like that in PHP?
Woah woah hold up people; I'm well aware of the & symbol but that's what I'm trying to avoid. As my question specifies (^) I'm looking for a version of the PHP array that is pass-by-reference by default
I'd like a version of the PHP array that feels, smells and looks like
the normal array, but is pass-by-reference. Is there anything like
that in PHP?
No, There is nothing like that in PHP.
Json encode should be able to pass objects. But if you for some reason NEED an array, you can't use objects and then cast it as array before encoding to json?
<?php
$object = (object)array("number"=>1);
function addToTen($object){
if($object->number<10){
$object->number++;
addToTen($object);
}
}
addToTen($object);
echo json_encode((array)$object);
//echoes {"number":10} with or without casting it as an array
?>
You could also wrap your array in an object of course, like this:
$object = new stdClass;
$object->a = array();
function fillUpArray($object){
if(count($object->a)<10){
$object->a[] = "someValue";
fillUpArray($object);
}
}
fillUpArray($object);
echo json_encode($object->a);
//echoes ["someValue","someValue","someValue","someValue","someValue","someValue","someValue","someValue","someValue","someValue"]
I must admit though I don't entirely get what you're trying to accomplish here :S
Yes, see the PHP manual page: http://php.net/manual/en/language.references.pass.php
Stop using &references altogether, in php they get cumbersome pretty quickly, (being, unlike C pointers, almost transparent, the only way to check you're actually using a reference is by assigning junk to it and check the effect this has on a tree) and you don't seem willing to handle that level of subtlety.
(Nor to wrap it with an ArrayObject, apparently)
Are you aware objects ARE references?
Object-wrap every aspect of your tree and your life will instantly get less miserable.
I am not aware of any such built-in functionality in PHP that you ask. Also, you are quite reluctant to use references. Hmmm...you could send a request to the PHP dev team to include such stuff in PHP v6, along with unicode that is supposed to come, that would us all happy :).
However, can you use a class and assign your initial array to one of the class variables and then process it and get it back after the recursion. Not sure if that would work, but anyway here it is:
<?php
class noReference {
public $myData;
public function __construct( $data ) {
$this->myData = $data; // this is your initial array.
}
// this function works on the myData array and changes it.
public function myRecursiveFunction() {
// your code here
$this->myRecursiveFunction(); // called as per your logic
// your code here
}
public function getData() {
return $this->myData;
}
public function __destruct() {
unset( $this->myData );
}
}
$data = array(/*WHATEVER_PLEASES_YOU*/);
$noref = new noReference( $data );
// this will be your recuresive function
$noref->myRecursiveFunction();
//your data here
$result = $noref->getData();
?>
Let me know if this works. Cheers!
you can force php to pass things by reference by adding an &-sign to the parameter. read the documentation for more information.

Categories