I have two arrays:
$info = array();
$submitted = array();
I declared an assignment below:
$info['idnumber'] = 10066;
$submitted[$info['idnumber']] = 'Wow';
array_multisort($submitted);
After doing so, displayed $submitted array.
foreach($submitted as $key => $row){
echo $key;
}
Why does it display 0 instead of 10066? I tried tweaking my code to:
$info['idnumber'] = 10066;
$submitted[(string)$info['idnumber']] = 'Wow';
or
$info['idnumber'] = 10066;
$submitted[strval($info['idnumber'])] = 'Wow';
Still it displays 0. What shall I do to display 10066 as the index of the $submitted array?
Update:
I found out it's a known bug of array_multisort, but still it has no solutions. Any idea how to fix ]it?
As you pointed out it is a known behaviour.
The solution was proposed in the discussion
For the moment I'm going to say prefix all your array keys with an extra 0 (or any non-numeric) to force their casting as strings.
When you try to cast integer into string like this:
(string)$info['idnumber']
you still get the integer, because you have a valid number as a string.
So you need to have a string as with some prefix. Prefix can be a 0 or any other non-numeric character. like an i
$info['idnumber'] = '010066';
Or
$info['idnumber'] = 'i00066';
This will return the exact index.
Related
Edit1: The problem: I want to convert in php a associative array to a indexed one. So I can return it via json_encode as an array and not as an object. For this I try to fill the missing keys. Here the description:
Got a small problem, I need to transfer a json_encoded array as an array to js. At the moment it returns an Object. I´m working with Angular so I really need an Array. I try to explain it as much as possible.
$arrNew[0][5][0][0][1]["id"] = 1;
//$arrNew[0][0][0][0][1] = "";
//$arrNew[0][1][0][0][1] = "";
//$arrNew[0][2][0][0][1] = "";
//$arrNew[0][3][0][0][1] = "";
//$arrNew[0][4][0][0][1] = "";
$arrNew[0][5][0][0][1]["name"] = 'Test';
var_dump($arrNew);
So if I return it now It returns the second element as object cause of the missing index 0-4 and the 4th element cause of the missing index 0 (associative array -> object)
So if I uncomment the block it works like a charm. Now I have the problem its not every time the element 5 sometime 3, 4 or something else so I build a function which adds them automaticly:
$objSorted = cleanArray($arrNew);
function cleanArray($array){
end($array);
$max = key($array) + 1; //Get the final key as max!
for($i = 0; $i < $max; $i++) {
if(!isset($array[$i])) {
$array[$i] = '';
} else {
end($array[$i]);
$max2 = key($array[$i]) + 1;
for($i2 = 0; $i2 < $max2; $i2++) {
.... same code repeats here for every index
So if I vardump it it returns:
The problem:
On js side its still an object, what I also see is that the elements are not sorted. So I think somehow PHP sees it still as an associative array. Any clue why this happens ? The key is set with the index of the loop and has to be a integer value.
PS: I know reworking it in JS is possible but would have be done nearly on every request with a huge load of loops
If I understand your problem, you create a sparse multidimensional array of objects. Because the arrays have gaps in the keys, json_encode() produces objects on some levels but you need it to produce arrays for all but the most inner level.
The following function fills the missing keys (starting from 0 until the maximum value used as numeric key in an array) on all array levels. It then sorts each array by their keys to make sure json_encode() encodes it as array and not object.
The sorting is needed, otherwise json_encode() generates an object; this behaviour is explained in a note on the json_encode() documentation page:
When encoding an array, if the keys are not a continuous numeric sequence starting from 0, all keys are encoded as strings, and specified explicitly for each key-value pair.
// If $arr has numeric keys (not all keys are tested!) then returns
// an array whose keys are a continuous numeric sequence starting from 0.
// Operate recursively for array values of $arr
function fillKeys(array $arr)
{
// Fill the numeric keys of all values that are arrays
foreach ($arr as $key => $value) {
if (is_array($value)) {
$arr[$key] = fillKeys($value);
}
}
$max = max(array_keys($arr));
// Sloppy detection of numeric keys; it may fail you for mixed type keys!
if (is_int($max)) {
// Fill the missing keys; use NULL as value
$arr = $arr + array_fill(0, $max, NULL);
// Sort by keys to have a continuous sequence
ksort($arr);
}
return $arr;
}
// Some array to test
$arrNew[0][5][0][0][1]["id"] = 1;
$arrNew[0][3][0][2][1]["id"] = 2;
$arrNew[0][5][0][0][1]["name"] = 'Test';
echo("============= Before ==============\n");
echo(json_encode($arrNew)."\n");
$normal = fillKeys($arrNew);
echo("============= After ==============\n");
echo(json_encode($normal)."\n");
The output:
============= Before ==============
[{"5":[[{"1":{"id":1,"name":"Test"}}]],"3":[{"2":{"1":{"id":2}}}]}]
============= After ==============
[[null,null,null,[[null,null,[null,{"id":2}]]],null,[[[null,{"id":1,"name":"Test"}]]]]]
The line $arr = $arr + array_fill(0, $max, NULL); uses NULL as values for the missing keys. This is, I think, the best for the Javascript code that parses the array (you can use if (! arr[0]) to detect the dummy values).
You can use the empty string ('') instead of NULL to get a shorter JSON:
[["","","",[["","",["",{"id":2}]]],"",[[["",{"id":1,"name":"Test"}]]]]]
but it requires slightly longer code on the JS side to detect the dummy values (if (arr[0] != '')).
I have the main array called $quizzes which contains the collection of $Quiz.
Each $Quiz has the following fields: $Quiz['correct'] gives me the number of correct questions.
I can get the number of correct questions for 12th quiz using $quizzes[12]['correct']
However, since these quizzes are not displayed in order, I decided to define a new array:
$listoftests = array('$quizzes[30]','$quizzes[51]');
In my head, $listoftests[0]['correct'] should be equal to $quizzes[30]['correct'] but it's giving me
Warning: Illegal string offset 'correct' in
/demo.php
on line 14 $
when I try to echo $listoftests[0]['correct'];
In this $listoftests = array('$quizzes[30]','$quizzes[51]'); These are considered as two strings $quizzes[30] and $quizzes[51]. You should remove single quotes ' and try again.
Change this:
$listoftests = array('$quizzes[30]','$quizzes[51]');
To:
$listoftests = array($quizzes[30],$quizzes[51]);
By doing this
$listoftests = array('$quizzes[30]','$quizzes[51]');
you created array of 2 strings. That's it. Not an array of arrays.
You should remove quotes. And you can also use isset() to check if array item exists.
Remove the single quote and it shell work fine $listoftests = array($quizzes[30],$quizzes[51]);
#GRS you can do it in two way:
//case one where the element will be of string type
<?php
$quizzes[30] = 3;
$quizzes[51] = 32;
$listoftests = array("$quizzes[30]","$quizzes[51]");
var_dump($listoftests);
//or
//case two where the element will be of integer type
<?php
$quizzes[30] = 3;
$quizzes[51] = 32;
$listoftests = array($quizzes[30],$quizzes[51]);
var_dump($listoftests);
I have an array and want to create a new numeric array. This looks like this:
$created_old = explode("_", $result[$i]["created"]);
$created_new = array();
$created_new[0] = $created_old[2];
$created_new[1] = $created_old[0];
$created_new[2] = $created_old[1];
$created_new[3] = "";
$created_new[4] = rtrim(explode(":", $created_old[3])[2], ")");
//Get name from the database
$created_new[3] = $name;
$created = implode("_", $created_new);
This version works just fine, but the previous was missing one line, so the code would be this:
$created_old = explode("_", $result[$i]["created"]);
$created_new = array();
$created_new[0] = $created_old[2];
$created_new[1] = $created_old[0];
$created_new[2] = $created_old[1];
//$created_new[3] = ""; - I am missing
$created_new[4] = rtrim(explode(":", $created_old[3])[2], ")");
//Get name from the database
$created_new[3] = $name;
$created = implode("_", $created_new);
In the second code the string $created is in the wrong order. The index 4 and 3 are switched. If it would be an associative array I would understand this but as it is an numeric array I assume the indices to increase numerically and beeing ordered like this. As I have a working version I do not need help to fix this code but rather understand why the code behaves as it does...
Best regards
JRsz
All PHP arrays are associative. There's no such thing as a "numeric array" expect in colloquial speech. A key can be either a string or a number, it doesn't matter. Keys are still ordered by their order of insertion and never implicitly ordered by their value. You would not be surprised by this behaviour I assume:
$arr['a'] = 1;
$arr['c'] = 3;
$arr['b'] = 2;
// ['a' => 1, 'c' => 3, 'b' => 2]
The exact same mechanics are at work in your "numeric array".
If you want to sort your keys, you need to do so explicitly using ksort.
Can someone explain the output of this code?
Why is it "fb" instead of "100100"?
$items = array();
$items[] = "foo";
$items[] = "bar";
foreach($items as $item) {
$item['points'] = 100;
}
foreach($items as $item) {
echo $item['points']; //output: "fb"
}
You loop though the $items array, which has two elements.
First: foo and second: bar. E.g.
Array (
[0] => foo
[1] => bar
)
Now you access them like this:
echo $item['points'];
PHP will convert points which is a string into an integer, as you can see from the manual warning:
Warning: [...] Non-integer types are converted to integer. [...]
Which in your case will be 0.
And so you access the two values (strings) as array:
string: f o o
index: 0 1 2 //$index["points"] -> $index[0]
string: b a r
index: 0 1 2 //$index["points"] -> $index[0]
So you print the first character of both strings (e.g. foo and bar), which are:
fb
EDIT:
Also worth to note here is, that PHP only silently converts it with PHP <5.4 from newer version you will get a warning, as from the manual:
As of PHP 5.4 string offsets have to either be integers or integer-like strings, otherwise a warning will be thrown. Previously an offset like "foo" was silently cast to 0.
Which in your case with PHP >=5.4 you would get:
Warning: Illegal string offset 'points' ...
I found this question intriguing.
I had my own walk-through and here is the result.
$items is defined as follows.
$items = [
0 => "foo",
1 => "bar"
];
Then, goes into the foreach loop.
foreach($items as $item) {
$item['points'] = 100;
}
At the beginning, $item contains a string "foo". The [] syntax is dominantly used for associative arrays, so it tricks us that $item might be an array, which is not the case. A less well-known usage of the [] is to get/set a single character in a string via [int] or {int} expression, as #Rizier123 has noted in his answer. For example, a "string"[0] gives "s". So, the following code
$item['points'] = 100;
is virtually similar to
"foo"['points'] = 100;
Now, a non-integer value given as a character position of a string, raises a PHP warning, and the position (here 'points') will be force-converted to an integer.
// Converting a string to integer:
echo intval('points'); // gives 0
As a result, the "foo"['points']" statement becomes "foo"[0], so
"foo"[0] = 100;
Now, the assignment part. The [] syntax operates on a single character. The numeric 100 is first converted to a string "100" and then only the first character is taken out for the assignment operation(=). The expression is now similar to
"foo"[0] = "1"; // result: "1oo"
To make things a bit twisted, the modified value of $item( which is "1oo") is not preserved. It's because the $item is not a reference. See https://stackoverflow.com/a/9920684/760211 for more information.
So, all the previous operations are negligible in terms of the end result. The $items are intact in the original state.
Now, in the last loop, we can see that the $item['point'] statement tries to read a character out of a string, in an erroneous way.
foreach($items as $item) {
echo $item['points']; //output: "fb"
}
echo "foo"[0]; // "f"
echo "boo"[0]; // "b"
You're not actually modifying the array by doing $items as $item. $item is its own variable, so it would make sense that you get the correct output when printing within that loop.
PHP.
$a['0']=1;
$a[0]=2;
Which is proper form?
In the first example you use a string to index the array which will be a hashtable "under the hood" which is slower. To access the value a "number" is computed from the string to locate the value you stored. This calculation takes time.
The second example is an array based on numbers which is faster. Arrays that use numbers will index the array according to that number. 0 is index 0; 1 is index 1. That is a very efficient way of accessing an array. No complex calculations are needed. The index is just an offset from the start of the array to access the value.
If you only use numbers, then you should use numbers, not strings. It's not a question of form, it's a question of how PHP will optimize your code. Numbers are faster.
However the speed differences are negligible when dealing with small sizes (arrays storing less than <10,000 elements; Thanks Paolo ;)
In the first you would have an array item:
Key: 0
Index: 0
In the second example, you have only an index set.
Index: 0
$arr = array();
$arr['Hello'] = 'World';
$arr['YoYo'] = 'Whazzap';
$arr[2] = 'No key'; // Index 2
The "funny" thing is, you will get exactly the same result.
PHP (for whatever reason) tests whether a string used as array index contains only digits. If it does the string is converted to int or double.
<?php
$x=array(); $x['0'] = 'foo';
var_dump($x);
$x=array(); $x[0] = 'foo';
var_dump($x);
For both arrays you get [0] => foo, not ["0"] => foo.
Or another test:<?php
$x = array();
$x[0] = 'a';
$x['1'] = 'b';
$x['01'] = 'c';
$x['foo'] = 'd';
foreach( $x as $k=>$v ) {
echo $k, ' ', gettype($k), "\n";
}0 integer
1 integer
01 string
foo string
If you still don't believe it take a look at #define HANDLE_NUMERIC(key, length, func) in zend_hash.h and when and where it is used.
You think that's weird? Pick a number and get in line...
If you plan to increment your keys use the second option. The first one is an associative array which contains the string "0" as the key.
They are both "proper" but have the different side effects as noted by others.
One other thing I'd point out, if you are just pushing items on to an array, you might prefer this syntax:
$a = array();
$a[] = 1;
$a[] = 2;
// now $a[0] is 1 and $a[1] is 2.
they are both good, they will both work.
the difference is that on the first, you set the value 1 to a key called '0'
on the second example, you set the value 2 on the first element in the array.
do not mix them up accidentally ;)