Array Key cannot be accesed - php

I have a little problem with the key of an array.
The array looks like this:
Array
(
[1] => Array
(
["question"] => test question 1
["open_response"] => 1
)
[2] => Array
(
["question"] => test question 2
["yes_no"] => 1
)
)
But for some reason whenever I try to access $data['1']['question'] it tells me that question is not an index. I'm a little confused about this since it should be a key but is not, how can I fix this? or how can i access it?

You want:
$data[1]['question']
Not:
$data['1']['question']
Edit:
My answer doesn't solve his problem, rather it helped him find the actual issue. The two snippets above are exactly the same thing because PHP will cast string keys into integers if the string is a valid integer. IMO, its confusing as hell. If I key my array with a string, dag`nammit it should be keyed with a string even if that string can also be parsed into an int!
The relevant documentation can be found here:
The key can either be an integer or a string. The value can be of any type.
Additionally the following key casts will occur:
Strings containing valid integers will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.
Floats are also cast to integers, which means that the fractional part will be truncated. E.g. the key 8.7 will actually be stored under 8.
Bools are cast to integers, too, i.e. the key true will actually be stored under 1 and the key false under 0.
Null will be cast to the empty string, i.e. the key null will actually be stored under "".
Arrays and objects can not be used as keys. Doing so will result in a warning: Illegal offset type.

Where are your array providing from?
Array indexes may have nonvisible (by your editor, browser etc) chars like backspace or null (\0) character. You can not see theese chars on var_dump.
Look this example :
code :
<pre>
<?php
$a = array(
"\0question\0" => "test question 1",
"question\0" => "test question 2",
"\0question" => "test question 3",
"question" => "test question 4"
);
var_dump($a);
?>
Output :
array(4) {
["question"]=>
string(15) "test question 1"
["question"]=>
string(15) "test question 2"
["question"]=>
string(15) "test question 3"
["question"]=>
string(15) "test question 4"
}
you can use some array functions like : array_values, array_map to rebuil and validate your array.

Related

php, array_merge_recursive works well with string keys only

$array1 = [
'1' => '11',
'b' => 1,
3 => 33,
8 => 8
];
$array2 = [
'1' => '22',
'b' => 2,
3 => 44,
9 => 9
];
$merged = array_merge_recursive($array1, $array2);
and the result is:
array(7) {
[0]=>
string(2) "11"
["b"]=>
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
[1]=>
int(33)
[2]=>
int(8)
[3]=>
string(2) "22"
[4]=>
int(44)
[5]=>
int(9)
}
so lets take a glance: the only part is the 'b' keys, they are actually works. I dont want to overwrite anything of it but putting them together to an array. Thats good! But then keys the other numeric keys (int or string) are screwed up.
I want to have this as result:
[
'1' => ['11', '22']
'b' => [1, 2]
[3] => [33, 44]
[8] => 8,
[9] => 9
]
possible?
EDIT: of course keys "1" and 1 - string vs int key are the same
Let's break down this question into to separate problems:
When a key in the second array exist in the first array, you want to create an array and make the value the first element of that array.
To be honest, I don't know an easy way of solving this. I'm not sure there is one. And even if, I'm not sure you really want it. Such a function will lead to arrays having values that are a string or an array. How would you handle such an array?
Update: Well, there is one. Your example already shows that array_merge_recursive will convert values with a string key into an array. So 1 => 'foo' would be 0 => 'foo', but 'foo' => 'bar' will end up as 'foo' => ['bar']. I really don't understand this behaviour.
Using string keys would help you out in this case, but after learning more about array_merge_recursive I decided to avoid this function when possible. After I asked this question someone filed it as a bug in it since PHP 7.0, since it works differently in PHP 5.x.
You want to keep the keys, while array_merge_resursive doesn't preserve integer keys, while it does for integer keys:
If the input arrays have the same string keys, then the values for
these keys are merged together into an array, and this is done
recursively, so that if one of the values is an array itself, the
function will merge it with a corresponding entry in another array
too. If, however, the arrays have the same numeric key, the later
value will not overwrite the original value, but will be appended.
To make it worse, it handles differently when handling the nested arrays:
$array1 = [30 => [500 => 'foo', 600 => 'bar']];
$array2 = [];
array_merge_recursive($array1, $array2);
//[0 => [500=> 'foo', 600 => 'bar']];
So effectively, array_merge_resursive isn't really resursive.
Using array_replace_resursive solves that problem:
array_replace_recursive($array1, $array2);
//output:
//array:5 [
// 1 => "22"
// "b" => 2
// 3 => 44
// 8 => 8
// 9 => 9
//]
Please note that PHP is very consistent in being inconsistent. While array_merge_recursive isn't recursive, array_replace_recursive doesn't replace (it also appends):
If the key exists in the second array, and not the first, it will be
created in the first array.
In many cases this is desired behavior and since naming functions isn't PHP's strongest point, you can consider this as a minor issue.
Can you rely on a native function to return your exact desired output? No. At least not in any version as of the date of this post (upto PHP8.1).
The good news is that crafting your own solution is very simple.
Code: (Demo)
foreach ($array2 as $key => $value) {
if (!key_exists($key, $array1)) {
$array1[$key] = $value;
} else {
$array1[$key] = (array)$array1[$key];
$array1[$key][] = $value;
}
}
var_export($array1);
I suppose I am less inclined to recommend this output structure because you have potentially different datatypes on a given level. If you were building subsequent code to iterate this data, you'd need to write conditions on every level to see if the data was iterable -- it just feels like you are setting yourself up for code bloat/convolution. I'd prefer a result which has consistent depth and datatypes.

Why few numbers are getting added after calling serialize on an associative array in PHP?

I've an array titled $aFilter. Upon serializing it few numbers are getting inserted into it. I'm not understanding why did it happen? Why did it insert the numbers and in which pattern? Can someone please guide me what actually this serialize() does and generates such kind of output in an easy way?
Following is my program :
<!DOCTYPE html>
<html>
<body>
<?php
$aFilter = Array(
'pages' => 1,
'photo' => 1,
'link' => 1,
'event' => 1,
'friend' => 1,
'user_status' => 1,
'poll' => 1,
'quiz' => 1,
'market' => 1,
'apps' => 1
);
echo serialize($aFilter);
?>
</body>
</html>
Output of above program is as follows :
a:10:{s:5:"pages";i:1;s:5:"photo";i:1;s:4:"link";i:1;s:5:"event";i:1;s:6:"friend";i:1;s:11:"user_status";i:1;s:4:"poll";i:1;s:4:"quiz";i:1;s:6:"market";i:1;s:4:"apps";i:1;}
Please help me out by making me understand this thing.
Thanks.
Lets first understand the meaning of serializing.
Serialize , according to the manual:
Generates a storable representation of a value
So we need to describe basically any value with a string in a way that we could also unserialize it later. So we're going to see a pattern that describes the serialized values which usually contains the type of value, length and value of course.
a:10{s:5:"pages";i:1;s:5:"photo";i:1;s:4:"link";i:1;s:5:"event";i:1;s:6:"friend";i:1;s:11:"user_status";i:1;s:4:"poll";i:1;s:4:"quiz";i:1;s:6:"market";i:1;s:4:"apps";i:1;}
Let's break your serialized string and compare it to your serialized object.
a:10 - a stands for Array ($aFilter = Array()) and the number 10 represents the number of elements in the array.
s:5:"pages" - s stands for String, 5 stands for the length of the value - since it's a string we can say that this is a amount of characters in the string. "pages" is the value itself. (Same for s:5:"photo", s:4:"link", etc.)
i:1 - i stands for Integer (number) and 1 is the value.
For instance, if instead of 'pages' => 1, you had 'bla' => 4,
the specific serialized part would be: s:3:"bla";i:4;
The "s" and "i" stay the same as we didn't change the type of the values,
but instead of 5 we have 3 since bla has 3 characters comparing to pages with 5, and instead of i:1 we have i:4 since now the value of that key is 4 and not 1.
In order to understand this part we need to notice that the we're serializing an array. So the engine needs to understand which part is the key and which part is the value. $array = array($key => $value);
In serialized string you'll notice that:
s:5:"pages";i:1;
s:5:"photo";i:1;
it's just a matter of order, first comes the key and then the value, and over again.(separated with ; of course).
I have to mention the link that #svengaly attached
which explain the whole "anatomy" of the serialization string. It's recommended to overview it if you're interested in further explanation and other scenarios.
http://php.net/manual/en/function.serialize.php#66147
Your serialized array is read as follows:
a:10:{ // array: 10 elements
s:5:"pages"; // string: 5 characters, value "pages"
i:1; // integer: value "1" (no number of digits is used for integers)
and so forth

PHP array with both a numbered index and named index?

I would think this would be easier to find but I've been scouring google with no luck. Can you create an array with both a numbered and named index? I know it has to be possible because mysqli_fetch_array returns one, but I can't find any reference to it.
Thanks.
As per official documentation:
An array in PHP is actually an ordered map. A map is a type that associates values to keys.
The key can either be an integer or a string. The value can be of any type.
Nothing to it:
$x = array();
$x['foo'] = 'bar';
$x[1] = 'baz';
Use any key you want. As long as whatever you're using for a key is an int or a valid string, it can be a key.
Yes. PHP arrays can have mixed keys (strings and integers). A reference to it can be found in the docs here: http://php.net/manual/en/language.types.array.php.
An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.
Check Example #3:
<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
100 => -100,
-100 => 100,
);
var_dump($array);
?>
outputs:
array(4) {
["foo"] => string(3) "bar"
["bar"] => string(3) "foo"
[100] => int(-100)
[-100] => int(100)
}

Associative Array Key Casting Float String

In my code, I have generated an associative array with keys as floats, however the PHP documentation states that when they become key's in the array they are SUPPOSED to be cast to integers. Instead, they are being cast to strings (which is actually better for me so I'm not complaining).
The problem is that when I try to access these keys using a float as the key value, it casts only the floats with .5 to integers and creates a new entry in the array. Seems like peculiar behavior.
Example:
var_dump( $array );
Output:
array(9) {
[0] =>
int(0)
[1.25] =>
int(0)
[2.5] =>
int(0)
....}
When I try to access the value 2.5 like so,
array[2.5]++;
a new entry in the array is made at array[2]
However if I try to access the array at array[1.25]++;
I successfully add 1 to the value at key: 1.25
Any ideas?
I would just stick with strings all the time:
$a = array(
'0' => 0,
'1.25' => 0,
'2.5' => 0
);
$a['2.5']++;
echo $a['2.5'] . "\n";
var_dump($a);
Output is:
1
array(3) {
[0]=>
int(0)
["1.25"]=>
int(0)
["2.5"]=>
int(1)
}

How to get keys/values from an incomplete associative array?

I have this kind of array:
$a = array(
'one' => 'one',
'0' => '0',
'two' => 'two',
'three' => 'three',
'four'
);
as you can see it is an associative array BUT not all the keys have the value (take a look at the last).
My question is, how can i loop this kind of array to get key(if exists) and the respective value?
Thank you!
The string 'four' in your example is not a key but a value. The corresponding key will be 1. This happens because PHP converts the string key '0' to numeric key 0 and for the value 'four' it uses the next numeric key which will be 1.
Reference:
A key may be either an integer or a string. If a key is the standard
representation of an integer, it will be interpreted as such (i.e. "8"
will be interpreted as 8, while "08" will be interpreted as "08")
To have a key with no value you can use NULL as the value:
'four' => null
Similarly to have an empty key use null as key:
null => 'four'
And to loop over such an array you can use a foreach loop. To detect if a key/value is null or not you can use the isset function.
With var_dump($a); you see all keys and values:
array(5) {
["one"] => string(3) "one"
[0] => string(1) "0"
["two"] => string(3) "two"
["three"] => string(5) "three"
[1] => string(4) "four"
}
you can use the foreach construction:
foreach($a as $key=>$val){
// $key is a current key
// $val is tha current value associated
}
As described in PHP: Arrays
A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08"). Floats in key are truncated to integer. The indexed and associative array types are the same type in PHP, which can both contain integer and string indices.
So you cannot distinguish key '0' and 0. And your last element is not a key, it is a value with auto incremental integer key 1. You can check with var_dump($a):
array(5) {
["one"]=>
string(3) "one"
[0]=>
string(1) "0"
["two"]=>
string(3) "two"
["three"]=>
string(5) "three"
[1]=>
string(4) "four"
}
If you can ensure all your keys do not start with digit, then you can just iterate the array as usual, and test the key using is_int.

Categories