PHP json_encode switching array to object in a particular server... why? - php

I have a library that read a directory and join a lot of information in a single object, so I can get it by JSON and work on it with JavaScript. I have a php that calls the lib for me and returns the JSON, simple as this:
echo('&vars_ini=OK&dados='.json_encode($Lista).'&vars_fim=');
After get the value of "dados", this is what I got:
{"erro":"OK","Lista":[{"nome":"a-process.gif","base":"a-process","ext":"gif","bytes":93117,"datac":"07\/04\/2016 13:46","datam":"31\/05\/2017 20:06","timestampc":1460047579,"timestampm":1496272006}, ... etc. there is also other lists as subdirectories.
But in this particular server, I am getting this:
{"erro":"OK","Lista":{"22":{"nome":"a-process.gif","base":"a-process","ext":"gif","bytes":93117,"datac":"03\/08\/2016 18:33","datam":"03\/08\/2016 18:26","timestampc":1470249183,"timestampm":1470248785},"43":{"nome":"g-agenda.gif","base":"g-agenda","ext":"gif","bytes":1454,"datac":"03\/08\/2016 18:33","datam":"03\/08\/2016 18:26","timestampc":1470249183,"timestampm":1470248786}, ... etc.
Instead of "Lista" be rendered with "[", there is a "{". My testing server is running php 5.6.10 and this server is 5.6.27. I don't think is a version problem (really?) but maybe some directive is telling to work like this.
The simple solution is to convert those objects to array, no big deal, but I am trying to understand why this is happening and to optimize my code.

You need to start your array at 0 and increment contiguously to get a JSON array. Failing that, use array_values() to re-index the PHP array before json_encode().
In your first example the array index starts at 0 so json_encode() treats it as an array. In the second the array index starts at 22 so it is treated as an object. The indexes also need to be contiguous to generate an array. Somehow you generate or get different indexes in each instance (maybe sorting or other function that defines or moves the indexes).
This shows contiguous indexes starting at 0:
$v = range(1,5);
print_r($v);
echo json_encode($v);
Yields an array:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
[1,2,3,4,5]
While starting at 1:
$k = range(1,5);
$z = array_combine($k, $v);
print_r($z);
echo json_encode($z);
Yields an object:
Array
(
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
{"1":1,"2":2,"3":3,"4":4,"5":5}
Starting at 0 with non-contiguous indexes:
$z = array(0, 2=>2, 3=>3, 5=>5);
print_r($z);
echo json_encode($z);
Yields an object:
Array
(
[0] => 0
[2] => 2
[3] => 3
[5] => 5
)
{"0":0,"2":2,"3":3,"5":5}

Related

PHP using key of one array to access same key position on another array

I've looked at a number of suggestions for this, and they seem to rely on array_combine() which unfortunately is not suitable, as they arrays need to stay separate for other functions.
The arrays are set out as per
Array ( [0] => 3 [1] => 1 [2] => 3 )
Array ( [0] => 194 [1] => 0 [2] => 452 )
When I read in the first array, I get the key as $key and everything works fine.
Whenever I try and access the second array the whole script just whites out the page.
I want the code to work simliar to this ...
$a2value = $a2[$key] => $value;
echo $a2value;
Then I can do SQL lookups using $a2value
Any help would be appreciated
Here Try this
let's suppose two arrays of same number of elements
$a1=[1,2,3];
$a2=[194,0,452];
//A Simple foreach
foreach($a1 as $key=>$a1value){
$a2value=$a2[$key];
//Perform Query here
}
Remember one thing number of elements of both array should always be equal or it will cause an error
If you aren't certain about the size of both arrays then replace the line with this code
$a2value=empty($a2[$key]) ? null : $a2[$key];
Hope this works !!!

Comparing arrays until I have a unique array

I have the following multidimensional array called $existing_combinations
Array
(
[0] => Array
(
[1] => 6
[2] => 7
[3] => 9
)
[1] => Array
(
[1] => 1
[2] => 21
[3] => 9
)
[2] => Array
(
[1] => 1
[2] => 7
[3] => 9
)
)
I then generate a new array ($new_combination) which has a combination of the same set of values. Example:
Array
(
[1] => 6
[2] => 21
[3] => 9
)
I then test if $new_combination exists in $existing_combinations with the following in the hope that I will end with a unique combination in $new_combination:
foreach($existing_combinations as $key => $combination){
while($new_combination == $combination){
$new_combination = generateNewCombination();
}
}
The problem is that if $new_combination matches an array that is not at index 0, then when I generate a new combination I am at risk of this matching a $combination that has already been tested against (and will not be tested again).
Sorry if this is a simple one but I'm struggling to think of how I can ensure $new_combination will always end up unique.
Any ideas?
Thanks
You can use in_array in this case, because php compares arrays as value. So, the code can be:
while(in_array($new_combination = generateNewCombination(), $existing_combinations));
print_r($new_combination);
I wrote the below before realizing that in_array can also see if an array exists within an array. So you can simply do this:
if (!in_array($new_combination, $existing_combinations)) {
// It's unique.
}
In the below outdated bit, see the note on using sort, if a different sequence of the same numbers isn't considered unique for your purposes.
[ For Entertainment ]
May not be the most elegant way around, but I would simply do this to keep it simple:
$combo_hashes = [];
// Implode the existing combos into strings.
foreach($existing as $vals) {
$combo_hashes[] = implode(':', $vals);
}
Then, all you need to check with your new combo is:
// Check if the "hash"-string already exists.
if (!in_array( implode(':', $new_combo), $combo_hashes)) {
// ... and we're unique.
}
This presumes that you consider [1,3,2] different from [2,1,3]. If they are equivalent (I don't know what your use case is), you should sort($vals); before you generate the check-strings.
Merge all the second level arrays and run array_unique() to get rid of the duplicate values.

Foreach and unset()

Ran into a little snag and wondering if there is a "best practices" way around it.
So I just learned that "A php foreach will execute on the entire array regardless. Test unsetting a value that is next in iteration. It will iterate on the offset, but the value will be null. – Kevin Peno Dec 22 '09 at 21:31" from How do you remove an array element in a foreach loop?
It's the first part of that that is messing with me. I'm iterating through an array with foreach. It's a search function so I'm removing the element I just searched for, so when the loop runs again its minus that element.
I do NOT want to reindex if at all possible, although if I have to I can.
Array
(
[0] => Array
(
[0] => a
[1] => aa
[2] => aaa
)
[1] => Array
(
[0] => b
[1] => bb
[2] => bbb
)
[2] => Array
(
[0] => c
[1] => cc
[2] => ccc
)
[3] => Array
(
[0] => d
[1] => dd
[2] => ddd
)
)
foreach($array as $key=>$value) {
$searchresult[] = search function returns various other keys from array
foreach($searchresult as $deletionid) {
unset($array[$deletionid]);
}
}
So on the first iteration it uses $array[0] obviously but the $searchresults might return 4,5,6,7. So those keys are removed from $array.
Yet the foreach loop still iterates through those and gives me back a bunch of empty arrays.
I did read How does PHP 'foreach' actually work? and I get some of it.
Thanks
In my opinion, the best way to remove array elements based on indexes is to use the array_* set of functions, like array_diff and array_intersect (or array_diff_key and array_intersect_key in your situation).
$indexes_to_remove = array(2,3,4);
$indexes_to_remove = array_flip($indexes_to_remove);
$array = array_diff_key($array,$indexes_to_remove);
If the array is guaranteed to be exhausted at some point, you can use this:
while (true) {
$searchresult[] = search function returns various other keys from array
foreach($searchresult as $deletionid) {
unset($array[$deletionid]);
}
if (count($array) === 0) {
break;
}
}
And yes I know while (true) is pretty evil, but I find in cases like these it does exactly what is needed.
If you want to prevent it from infinite looping you could always add a variable, increment each iteration, and break when it reaches a high value that should never happen (like 10 * count($array))

I honestly have no clue how to formulate this pass-by-reference conundrum

So here's what I see this code doing:
An array is made
A loop iterates 10 times
A new array is created
A reference to this new array is saved in the first array
10 arrays now reside in the original array with values 0, 1, 2, 3...
What really happens:
WTF?
Code:
<?php
header('Content-type: text/plain');
$arrays = array();
foreach(range(0, 10) as $i)
{
$arr = array();
$arr[0] = $i;
$arrays[] = &$arr;
}
print_r($arrays);
Output:
Array
(
[0] => Array
(
[0] => 10
)
[1] => Array
(
[0] => 10
)
[2] => Array
(
[0] => 10
)
[3] => Array
(
[0] => 10
)
[4] => Array
(
[0] => 10
)
[5] => Array
(
[0] => 10
)
[6] => Array
(
[0] => 10
)
[7] => Array
(
[0] => 10
)
[8] => Array
(
[0] => 10
)
[9] => Array
(
[0] => 10
)
[10] => Array
(
[0] => 10
)
)
I would like to know exactly why apparently only the 10th array is referred to ten times, instead of every instance of the arrays being referred to one each.
Also if somebody who isn't just thinking WTF (like me) would like to edit the title, feel free to do so.
The line
$arr = array();
does not create a new array but rather assigns an empty array to the already existing reference.
If you want the variable name to "point" to a different array in memory, you have to unset() (or "disconnect") it first before assigning an empty array to it:
foreach(range(0, 10) as $i)
{
unset($arr);
$arr = array();
$arr[0] = $i;
$arrays[] = &$arr;
}
This is because the only operations that can make a variable point to something else is the reference assignment (=&) and the unset().
What happens here is that by inserting a reference to $arr inside $arrays, you are effectively adding the exact same array 10 times -- and each reference to the array has the value last assigned to it (i.e. the one produced when $i is 10).
It's not clear what you intend to achieve by inserting a reference in each iteration -- either removing the & or putting unset($arr) at the beginning of the loop would give you the expected behavior. What are you trying to accomplish?
Think about it this way. You do $arrays[] = &$arr; 10 times. This stores a reference to the local variable $arr 10 times. Since it's the same variable (the variable's scope is the entire function), it stores the same reference all 10 times. Thus, why should you expect the 10 elements to be different?
The reference you are storing has nothing to do with the value of $arr; it just has to do with the variable $arr. When you print the reference it prints the value of $arr at that time.
It's because you're storing a reference to the array that $arr points to in the array. And you keep overwriting that array with the latest number. All references in $arr will point to the same array in the end.
I don't know what you expect to get out of this in the end, but getting rid of & should fix this behavior.

PHP Aligning Array Key Values

I've Googled it for two days, and tried looking at the PHP manual, and I still can't remember that function that aligns the key values for PHP arrays.
All I'm looking for is the function that takes this:
Array
(
[0] => 1
[3] => 2
[4] => 3
[7] => 4
[9] => 5
)
And converts it into this:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
Basically, the array is first sorted by key (their values attached to them stay with them), then all the keys are set to all the counting numbers, consecutively, without skipping any number (0,1,2,3,4,5,6,7,8,9...). I saw it being used with ksort() a few months ago, and can't see to remember or find this elusive function.
Well, you see, this one is hard, because the general description on the PHP array functions page does not say that this function does what you're looking for.
But you can sort the array using ksort(), and then use this: array_values() . From the page from the PHP manual:
array_values() returns all the values from the input array and indexes numerically the array.
You can use array_merge:
$array = array_merge($array);
It will reindex values with numeric keys.
Update: Using array_values as proposed in #LostInTheCode's answer is probably more descriptive.
function array_reset_index_keys($array)
{
$return = array();foreach($array as $k => $v){$return[] = $v;}return $return;
}
And then use like a regular function, should re index the array
you can also use native functions such as array_values which returns the values of an array into a single dimension array, causing it to be re indexed .

Categories