如何强制PHP使用字符串作为数组键?

ale*_*lex 56 php arrays

我遇到过一个使用id命名类型数组的旧应用程序,例如......

array(1) {
  [280]=>
  string(3) "abc"
}
Run Code Online (Sandbox Code Playgroud)

现在我需要对这些进行重新排序,并且var_dump()当键是整数时,这似乎不会发生.

如果我a为每个索引添加一个,var_dump()将在键周围显示双引号,我的猜测显示它现在是一个字符串...

array(1) {
  ["280a"]=>
  string(3) "abc"
}
Run Code Online (Sandbox Code Playgroud)

这样我就可以轻松地对它们进行重新排序,而无需触及更多代码.

这并不起作用.

$newArray = array();
foreach($array as $key => $value) {
   $newArray[(string) $key] = $value;
}
Run Code Online (Sandbox Code Playgroud)

A var_dump()仍然将它们显示为整数数组索引.

有没有办法强制键成为字符串,所以我可以重新排序它们而不破坏数组?

Tar*_*nes 15

你不能!!

包含有效整数的字符串将强制转换为整数类型.例如,键"8"实际上将存储在8下.另一方面,"08"将不会被转换,因为它不是有效的十进制整数.

编辑:

实际上你可以!! 将顺序数组转换为关联数组

$obj = new stdClass;
foreach($array as $key => $value){
    $obj->{$key} = $value;
}
$array = (array) $obj;
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,以下引用它是正确的.

包含有效整数的字符串将强制转换为整数类型.例如,键"8"实际上将存储在8下.另一方面,"08"将不会被转换,因为它不是有效的十进制整数.

这个例子来自PHP Docs

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

上面的例子将输出:

array(1) {
  [1]=> string(1) "d"
}
Run Code Online (Sandbox Code Playgroud)

因此,即使您要使用数字键创建一个数组,它们也会被转换回整数.

不幸的是,直到最近我才意识到这一点,但我会分享我失败的尝试.

尝试失败

$arr = array_?change_?key_?case($arr); // worth a try. 
Run Code Online (Sandbox Code Playgroud)

返回一个数组,其中包含来自数组小写或大写的所有键.编号索引按原样保留.

我的下一次尝试是通过array_combine旧值(新的(字符串)键)创建一个新数组.

我尝试了几种方法使$keys数组包含string类型的数值.

range("A", "Z" ) 适用于字母表,所以我会尝试使用数字字符串.

$keys = range("0", (string) count($arr) ); // integers
Run Code Online (Sandbox Code Playgroud)

这导致了一个充满键的数组,但都是int类型.

以下是使用string类型值创建数组的几次成功尝试.

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

$keys = array_map('strval', array_keys($arr)); // values strings
Run Code Online (Sandbox Code Playgroud)

现在只是将两者结合起来.

$arr = array_combine( $keys, $arr); 
Run Code Online (Sandbox Code Playgroud)

这是我发现数字字符串被转换为整数的时候.

$arr = array_combine( $keys, $arr); // int strings
//assert($arr === array_values($arr)) // true. 
Run Code Online (Sandbox Code Playgroud)

将键更改为字符串并保持其字面值的唯一方法是在键前面加上带小数点的后缀"00","01","02""0.","1.","2.".

你可以这样做.

$keys = explode(',', implode(".,", array_keys($arr)) . '.'); // added decimal point 
$arr = array_combine($keys, $arr);
Run Code Online (Sandbox Code Playgroud)

当然这不太理想,因为你需要像这样定位数组元素.

$arr["280."]   
Run Code Online (Sandbox Code Playgroud)

我已经创建了一个小函数,它将定位正确的数组元素,即使您只输入整数而不是新字符串.

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;
}
Run Code Online (Sandbox Code Playgroud)

用法

echo array_value($array, "208"); // "abc"
Run Code Online (Sandbox Code Playgroud)

编辑:

实际上你可以!! 将顺序数组转换为关联数组

一切都是无用的

  • @丹尼尔W。“208”是一个字符串,而不是一个整数!208 是一个整数 使用数字作为关联数组键并没有什么“坏处”。如果高级语言在内部将该数字字符串转换为整数并且现在访问错误的元素,这只会变得很糟糕。这是不一致的,并且显示出从实施 php 基础知识起就缺乏专业精神。由于 PHP 的老化,要在没有副作用的情况下改变这种行为可能变得很困难。最严重的安全漏洞就是由这种实现产生的。 (5认同)
  • 在 2021 年 PHP 8 中仍然有效。这在 PHP 方面确实是一个糟糕的行为。您的解决方案可能有效,它更多的是滥用 PHP 不一致中的错误,但性能影响可能很大。 (3认同)

pro*_*son 8

编辑:

我假设如果它们是整数,我不能在不更改密钥的情况下对它们重新排序(这在本例中很重要).但是,如果它们是字符串,我可以重新排序它们的喜好,因为索引不应被解释为具有任何特殊含义.无论如何,请看我的问题更新我是如何做到的(我走了一条不同的路线).

实际上他们不必按数字顺序排列......

array(208=>'a', 0=> 'b', 99=>'c');
Run Code Online (Sandbox Code Playgroud)

如果您手动分配它们,则完全有效.虽然我同意整数键可能被误解为某人具有连续意义,尽管你会认为如果它们是非数字顺序,那么很明显它们不是.这就是说我认为,因为你有更新代码的余地,因为你更新了这是更好的方法.


可能不是最有效的方式,但很容易就像馅饼一样:

$keys = array_keys($data);

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

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

//sort your data
Run Code Online (Sandbox Code Playgroud)

  • 我知道这是旧的,但非常烦人的问题.看起来PHP会在为数组创建密钥时将"数字字符串"(我猜想的整数字符串)转换为整数.这是错误报告:https://bugs.php.net/bug.php?id = 45348&edit = 3 (2认同)

小智 8

使用对象而不是数组 $object = (object)$array;


Tim*_*ard 5

您可以将空字符附加"\0"到数组键的末尾。这样一来,PHP就无法将字符串解释为整数。所有的数组函数(如array_merge())都可以在其上工作。也不会var_dump()在整数字符串之后显示任何多余的内容。

例:

$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);
Run Code Online (Sandbox Code Playgroud)

结果输出将是:

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"
}
Run Code Online (Sandbox Code Playgroud)

没有这个. "\0"部分,结果数组将是:

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"
}
Run Code Online (Sandbox Code Playgroud)

ksort()将忽略空字符的含义,$numbers[111]并且$numbers["111\0"]在排序算法中将具有相同的权重。

这种方法的唯一缺点是,例如$numbers["444"],您实际上必须通过来访问它,$numbers["444\0"]并且由于甚至var_dump()都不会显示出末尾有一个空字符,因此不知道为什么会出现“未定义的偏移量”。因此,仅当通过foreach()或最终维护您的代码的人讨厌您时才使用此hack 。