How can I force PHP to use strings for array keys?

PhpArrays

Php Problem Overview


I've come across an old app that uses an id to name type array, for example...

array(1) {
  [280]=>
  string(3) "abc"
}

Now I need to reorder these, and a var_dump() would make it appear that that isn't going to happen while the keys are integers.

If I add an a to every index, var_dump() will show double quotes around the key, my guess to show it is now a string...

array(1) {
  ["280a"]=>
  string(3) "abc"
}

This would let me easily reorder them, without having to touch more code.

This does not work.

$newArray = array();
foreach($array as $key => $value) {
   $newArray[(string) $key] = $value;
}

A var_dump() still shows them as integer array indexes.

Is there a way to force the keys to be strings, so I can reorder them without ruining the array?

Php Solutions


Solution 1 - Php

YOU CAN'T!! > 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.

Edit:

ACTUALLY YOU CAN!! Cast sequential array to associative array

$obj = new stdClass;
foreach($array as $key => $value){
    $obj->{$key} = $value;
}
$array = (array) $obj;

In most cases, the following quote is true: > 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.

This examples from the PHP Docs

 <?php
    $array = array(
        1    => "a",
        "1"  => "b",
        1.5  => "c",
        true => "d",
    );
    var_dump($array);
?>

The above example will output:

array(1) {
  [1]=> string(1) "d"
}

So even if you were to create an array with numbered keys they would just get casted back to integers.

Unfortunately for me I was not aware of this until recently but I thought I would share my failed attempts.

Failed attempts

$arr = array_​change_​key_​case($arr); // worth a try. 

> Returns an array with all keys from array lowercased or uppercased. Numbered indices are left as is.

My next attempts was to create a new array by array_combineing the old values the new (string)keys.

I tried several ways of making the $keys array contain numeric values of type string.

range("A", "Z" ) works for the alphabet so I though I would try it with a numeric string.

$keys = range("0", (string) count($arr) ); // integers

This resulted in an array full of keys but were all of int type.

Here's a couple of successful attempts of creating an array with the values of type string.

$keys = explode(',', implode(",", array_keys($arr))); // values strings

$keys = array_map('strval', array_keys($arr)); // values strings

Now just to combine the two.

$arr = array_combine( $keys, $arr); 

This is when I discovered numeric strings are casted to integers.

$arr = array_combine( $keys, $arr); // int strings
//assert($arr === array_values($arr)) // true. 

The only way to change the keys to strings and maintain their literal values would be to prefix the key with a suffix it with a decimal point "00","01","02" or "0.","1.","2.".

You can achieve this like so.

$keys = explode(',', implode(".,", array_keys($arr)) . '.'); // added decimal point 
$arr = array_combine($keys, $arr);

Of course this is less than ideal as you will need to target array elements like this.

$arr["280."]   

I've created a little function which will target the correct array element even if you only enter the integer and not the new string.

function array_value($array, $key){

    if(array_key_exists($key, $array)){
        return $array[ $key ];
    }
    if(is_numeric($key) && array_key_exists('.' . $key, $array)){
        return $array[ '.' . $key ];
    } 
    return null;
}

Usage

echo array_value($array, "208"); // "abc"

Edit:

ACTUALLY YOU CAN!! Cast sequential array to associative array

All that for nothing

Solution 2 - Php

You can append the null character "\0" to the end of the array key. This makes it so PHP can't interpret the string as an integer. All of the array functions (like array_merge()) work on it. Also not even var_dump() will show anything extra after the string of integers.

Example:

$numbers1 = array();
$numbers2 = array();
$numbers = array();

$pool1 = array(111, 222, 333, 444);
$pool2 = array(555, 666, 777, 888);

foreach($pool1 as $p1)
{
    $numbers1[$p1 . "\0"] = $p1;
}
foreach($pool2 as $p2)
{
    $numbers2[$p2 . "\0"] = $p2;
}

$numbers = array_merge($numbers1, $numbers2);

var_dump($numbers);

The resulting output will be:

array(8) {
    ["111"] => string(3) "111"
    ["222"] => string(3) "222"
    ["333"] => string(3) "333"
    ["444"] => string(3) "444"
    ["555"] => string(3) "555"
    ["666"] => string(3) "666"
    ["777"] => string(3) "777"
    ["888"] => string(3) "888"
}

Without the . "\0" part the resulting array would be:

array(8) {
    [0] => string(3) "111"
    [1] => string(3) "222"
    [2] => string(3) "333"
    [3] => string(3) "444"
    [4] => string(3) "555"
    [5] => string(3) "666"
    [6] => string(3) "777"
    [7] => string(3) "888"
}

Also ksort() will also ignore the null character meaning $numbers[111] and $numbers["111\0"] will both have the same weight in the sorting algorithm.

The only downside to this method is that to access, for example $numbers["444"], you would actually have to access it via $numbers["444\0"] and since not even var_dump() will show you there's a null character at the end, there's no clue as to why you get "Undefined offset". So only use this hack if iterating via a foreach() or whoever ends up maintaining your code will hate you.

Solution 3 - Php

Use an object instead of an array $object = (object)$array;

Solution 4 - Php

EDIT:

> I assumed that if they are integers, I > can't reorder them without changing > the key (which is significant in this > example). However, if they were > strings, I can reorder them how they > like as the index shouldn't be > interpreted to have any special > meaning. Anyway, see my question > update for how I did it (I went down a > different route).

Actually they dont have to be in numeric order...

array(208=>'a', 0=> 'b', 99=>'c');

Is perfectly valid if youre assigning them manually. Though i agree the integer keys might be misinterpreted as having a sequential meaning by someone although you would think if they were in a non-numeric order it would be evident they werent. That said i think since you had the leeway to change the code as you updated that is the better approach.


Probably not the most efficient way but easy as pie:

$keys = array_keys($data);

$values = array_values($data);
$stringKeys = array_map('strval', $keys);

$data = array_combine($stringKeys, $values);

//sort your data

Solution 5 - Php

I was able to get this to work by adding '.0' onto the end of each key, as such:

$options = [];
for ($i = 1; $i <= 4; $i++) {
    $options[$i.'.0'] = $i;
}

Will return:

array("1.0" => 1, "2.0" => 2, "3.0" => 3, "4.0" => 4)

It may not be completely optimal but it does allow you to sort the array and extract (an equivalent of) the original key without having to truncate anything.

Solution 6 - Php

Edit: This should work

foreach($array as $key => $value) { 
    $newkey = sprintf('%s',$key);
    $newArray["'$newkey'"] = $value; 
} 

Solution 7 - Php

Hi we can make the index of the array a string using the following way. If we convert an array to xml then indexes like [0] may create issue so convert to string like [sample_0]

$newArray = array();
foreach($array as $key => $value) {
   $newArray["sample_".$key] = $value;
}

Solution 8 - Php

Only one commenter got this right, and the accepted answer is bad. asort(), uasort(), and arsort() are built-ins that sort arrays whilst maintaining the key associations, and they've existed since version 4. RTFM, people.

Don't escape/corrupt your data by messing with keys. You can't stop PHP from using integer keys, so don't try. It only happens when the integer representation is exactly the same as the string, so you just cast them as such when reading the keys & values from the array, i.e. (string) $key. You can do all the sort operations you need using the aforementioned functions.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionalexView Question on Stackoverflow
Solution 1 - PhpTarranJonesView Answer on Stackoverflow
Solution 2 - PhpTim AagaardView Answer on Stackoverflow
Solution 3 - PhpPaul-Emile MINYView Answer on Stackoverflow
Solution 4 - PhpprodigitalsonView Answer on Stackoverflow
Solution 5 - PhpNeuroXcView Answer on Stackoverflow
Solution 6 - Phpuser387302View Answer on Stackoverflow
Solution 7 - PhpRamya AravindView Answer on Stackoverflow
Solution 8 - PhpWalfView Answer on Stackoverflow