在PHP中将数字字符串作为数组键名

129

在 PHP 数组中,是否可以使用数字字符串(如 "123")作为键名,而不会被转换为整数?

$blah = array('123' => 1);
var_dump($blah);

打印

array(1) {
  [123]=>
  int(1)
}

我想要

array(1) {
  ["123"]=>
  int(1)
}

9
由于 PHP 是弱类型语言,对于几乎所有目的而言,"123" == 123。那么为什么你特别需要它作为一个字符串(以及有一个整数是不好的)? - ircmaxell
23
我想到的原因与数组函数有关,比如array_merge。*"如果输入的数组具有相同的字符串键,则该键的后一个值将覆盖前一个值。但是,如果数组包含数字键,则后一个值不会覆盖原始值,而是会被追加。"* - ficuscr
9
另一个数值字符串作为数组键会出现问题的例子是 asort 函数。 - swenedo
2
可能是重复的问题,参考如何强制PHP使用字符串作为数组键? - nawfal
5
另一个使用案例:单元测试JSON数据转换。将这样的数组转换为JSON格式再转回去并不能让你断言原始数据和结果完全相同。 - David
显示剩余5条评论
11个回答

101

不是的;不,它不是:

来自手册

键名可以是整数或字符串。如果一个键名是整数的标准表现形式,它将被作为整数解析(例如,“8”将被解析为8,而“08”将被解析为“08”)。

补充说明

由于下面的评论,我想指出这种行为与JavaScript对象键的行为类似,但不是完全相同的。

foo = { '10' : 'bar' };

foo['10']; // "bar"
foo[10]; // "bar"
foo[012]; // "bar"
foo['012']; // undefined!

5
看起来实际上有一种方法!你不同意这个答案吗?https://dev59.com/BW855IYBdhLWcg3w3Ifs#35180513 - Flimm
1
怎么做?!.. foo[012] 返回 "bar" - Himanshu
4
@Himanshu: 因为 PHP 将以 0 开头的数字解释为八进制数,所以 012 被解释为八进制的 10。 - Yeasir Arafat Majumder
是的,可以使用以下代码实现:$dtmf_arr = array(); foreach ($_POST['dtmf'] as $val) { $dtmf_arr['"'.$val.'"'] = $dtmf[$val]; } - Darshit Mendapara
此外,有很多方法可以解决这个问题,例如使用数组加法+代替合并,或使用许多内置函数来保留键。如果您需要在从数组中读取时再次将键作为字符串使用,则将其转换为字符串可以保证返回原始值。 - Walf
显示剩余2条评论

59
是的,可以通过将stdClass对象转换为数组实现:
$data =  new stdClass;
$data->{"12"} = 37;
$data = (array) $data;
var_dump( $data );

这将适用于PHP版本7.1及以下:

array(1) {
  ["12"]=>
  int(37)
}

(更新:我的原始答案展示了一种更为复杂的方法,使用json_decode()json_encode(),但这是不必要的。)

注意评论:不幸的是,直接引用值是不可能的:$data['12']会导致一个提示。

更新:
从PHP 7.2开始,也可以使用数字字符串作为键来引用值:

var_dump( $data['12'] ); // int 32

3
使用字符串作为键名直接访问变量的值无法正常运行。请在您的示例中添加这一行代码:echo $data['12'];。这将会产生一个错误提示:"Notice: Undefined offset: 12 in - on line 5"。 - Mr. Lance E Sloan
2
在PHP 7.2.0RC2中,行为与以前相同。 - dev0
2
显然,在旧版本中,array_key_exists也找不到它。 - Don't Panic
1
这仅适用于>5.0 <7.1.33。 - Tomáš Fejfar
1
我的使用情况是需要在许多地方将“01”到“12”作为键,但在一个地方需要反向顺序。原始顺序现在可以工作(12/2022),但array_reverse()不能用于对象,并且在原始数组上真正破坏了它。一个可行的解决方案可能是array_flip(array_reverse(array_flip($original))),因为我只有(唯一的)月份名称作为值。 - Adam P.
显示剩余5条评论

13

我的解决方法是:

$id = 55;
$array = array(
  " $id" => $value
);

空格字符(prepend)是一个好的解决方案,因为它保持了整数转换:

foreach( $array as $key => $value ) {
  echo $key;
}

你会看到数字55以整数形式呈现。


4
"0$id" => $value也可以写成在$id前加上0。 - nawfal
那么您的意思是,在PHP数组中不能使用数字字符串(如“123”)作为键,而不将其转换为整数? - Flimm
@Flimm 是的,这是不可能的。无论如何都不可能使用“数组”类型。 - Danon

12
如果你需要在PHP数据结构中使用数字键,那么使用一个对象是可行的。而且对象会保留顺序,因此你可以进行迭代。
$obj = new stdClass();
$key = '3';
$obj->$key = 'abc';

这是一个非常好的建议。我正在编写框架代码,遇到有人传递一个数组,该数组可能具有“意外”索引:array('this', 'that')或“关联”索引:array(123=>array('this', 'that'))。现在,多亏了你,我可以使用类型提示;) +1 - user651390
但是在PHP数组中,是否可能使用数字字符串(如“123”)作为键,而不将其转换为整数? - Flimm
@Flimm 不,那是不可能的,这就是为什么我提供了自己的解决方案。 - steampowered
@Flimm 那个回答似乎与PHP手册相矛盾: 包含有效整数的字符串将被转换为整数类型。例如,键“8”实际上将存储在8下面。另一方面,“08”将不会被转换,因为它不是有效的十进制整数。 尽管如此,我还没有测试过他的答案。 - steampowered
@Flimm,对我来说,基于已测试的行为构建代码听起来很冒险,因为手册中可能不支持数据结构。对我来说,这就像依赖于JavaScript引擎支持对象属性顺序一样,它没有得到官方支持,并且在不同版本和不同平台上实现方式也不同。换句话说,David的答案在其他PHP版本中可能无法正常工作,并且如果您将来升级PHP,则可能停止工作。 - steampowered
显示剩余2条评论

5

您可以将键强制转换为字符串,但由于PHP的松散类型,它最终会被转换为整数。请自行查看:

$x=array((string)123=>'abc');
var_dump($x);
$x[123]='def';
var_dump($x);

来自PHP手册:

键可以是整数或字符串。如果一个键是整数的标准表示形式,它将被解释为整数(例如,“8”将被解释为8,而“08”将被解释为“08”)。键中的浮点数将被截断为整数。在PHP中,索引数组和关联数组类型是相同的类型,两者都可以包含整数和字符串索引。


1
转换不是由于松散的类型而发生的;PHP 确定字符串是否看起来是数字,然后进行转换。 - Ja͢ck
1
那么你的意思是说这不可能吗?这个答案表明有一种方法可以使用看起来像整数的字符串作为数组中的键。 - Flimm
在我看来,问题出在 PHP 解释器上。甚至无法想象一种将字符串和整数混合作为数组键的语言。最好的解决方案是什么?正如 Undolog 在 https://dev59.com/BW855IYBdhLWcg3w3Ifs#15413637 中提出的那样,最好的解决方案是使用尾随空格...可悲的是。 - sentenza
@sentenza:这是可能的,特别是因为PHP允许将字符串和整数混合作为数组的键:[42 => 'answer', 'snafu' => 'fubar'] - Mr. Lance E Sloan
@LS 是的。我知道 PHP 允许这样做,但是如果您考虑一个假想的通用类型系统中的键,它不会匹配任何同时包含字符串和数字的 混合类型。应用于关联数组键的松散类型只会带来错误。 - sentenza

3

我曾经遇到过一个问题,想要合并同时包含字符串和整数键的数组。由于其中的整数键是输入字段的名称(例如鞋码等),因此很重要将其视为字符串处理。

当我使用$data = array_merge($data, $extra);时,PHP会“重新排序”键。在尝试排序时,整数键(我尝试使用6- '6'-"6"以及(string)"6"作为键)从0到n被重命名...如果你考虑一下,在大多数情况下这应该是期望的行为。

您可以通过使用$data = $data + $extra;来解决这个问题。非常简单,但我起初没有考虑到 ^^。


1
完全相同的问题也让我来到了这个页面,但我必须说这不是对楼主问题的答案。 - Flimm
@Flimm 是的。但是寻找答案引导我来到了这个页面。我想我的解决方案可能对其他使用谷歌搜索的人有所帮助 :) - Brainfeeder

1
作为解决方法,您可以使用JSON_FORCE_OBJECT选项将PHP数组编码为JSON对象。 例如,这个例子:
     $a = array('foo','bar','baz');
     echo "RESULT: ", json_encode($a, JSON_FORCE_OBJECT);

将产生以下结果:

     RESULT: {"0" : "foo", "1": "bar", "2" : "baz"}

需要注意的是,这也会强制所有子数组成为对象,这可能无法产生预期的输出,请参见json_encode($a, JSON_FORCE_OBJECT)json_encode((object) $a)之间的区别 - Walf

0
关于@david的解决方案,请注意当您尝试访问关联数组中的字符串值时,数字将无法正常工作。我的猜测是它们在访问数组时被强制转换为整数,并且找不到任何值。访问整数值也行不通。但是,您可以使用array_shift()来获取值或迭代数组。
$data = new stdClass;
$data->{"0"} = "Zero";
$data->{"1"} = "One";
$data->{"A"} = "A";
$data->{"B"} = "B";

$data = (array)$data;

var_dump($data);
/*
Note the key "0" is correctly saved as a string:
array(3) {
  ["0"]=>
  string(4) "Zero"
  ["A"]=>
  string(1) "A"
  ["B"]=>
  string(1) "B"
}
*/

//Now let's access the associative array via the values 
//given from var_dump() above:
var_dump($data["0"]); // NULL -> Expected string(1) "0"
var_dump($data[0]); // NULL (as expected)
var_dump($data["1"]); // NULL -> Expected string(1) "1"
var_dump($data[1]); // NULL (as expected)
var_dump($data["A"]); // string(1) "A" (as expected)
var_dump($data["B"]); // string(1) "B" (as expected)

哪个 PHP 版本?我尝试了你的例子,使用 PHP 7.2.10,键“0”变成了 0 - J.BizMai

0
字符串包含有效整数将被转换为整数类型。例如,键“8”实际上将存储在8下。另一方面,“08”不会被转换,因为它不是有效的十进制整数。
错误
我有一个转换函数,可以处理顺序到关联数组的转换。
$array_assoc = cast($arr,'array_assoc');

$array_sequential = cast($arr,'array_sequential');

$obj = cast($arr,'object');

$json = cast($arr,'json');



function cast($var, $type){

    $orig_type = gettype($var);

    if($orig_type == 'string'){

        if($type == 'object'){
            $temp = json_decode($var);
        } else if($type == 'array'){
            $temp = json_decode($var, true);
        }
        if(isset($temp) && json_last_error() == JSON_ERROR_NONE){
            return $temp;
        }
    }
    if(@settype($var, $type)){
        return $var;
    }
    switch( $orig_type ) {

        case 'array' :

            if($type == 'array_assoc'){

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

            } else if($type == 'array_sequential'){

                return array_values($var);

            } else if($type == 'json'){

                return json_encode($var);
            }
        break;
    }
    return null; // or trigger_error
}

2
这个不起作用。如果键是有效的整数,则关联数组键仍将是整数。 - geoffs3310

0
我在一个包含'0'和''作为键的数组中遇到了这个问题。这意味着我无法使用==或===来检查我的数组键。
$array=array(''=>'empty', '0'=>'zero', '1'=>'one');
echo "Test 1\n";
foreach ($array as $key=>$value) {
    if ($key == '') { // Error - wrongly finds '0' as well
        echo "$value\n";
    }
}
echo "Test 2\n";
foreach ($array as $key=>$value) {
    if ($key === '0') { // Error - doesn't find '0'
        echo "$value\n";
    }
}

解决方法是在使用之前将数组键强制转换为字符串。

echo "Test 3\n";
foreach ($array as $key=>$value) {
    if ((string)$key == '') { // Cast back to string - fixes problem
        echo "$value\n";
    }
}
echo "Test 4\n";
foreach ($array as $key=>$value) {
    if ((string)$key === '0') { // Cast back to string - fixes problem
        echo "$value\n";
    }
}

1
这并不是对问题的真正回答。 - Flimm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接