早上看到 SO 上一个有关 PHP 的问题,提问者描述有一个数组,使用 print_r 可以看到索引 key 和相对应的 value 都是存在的,但是访问该元素,不管是使用 array[key] 还是 array[‘key’] 这两种访问形式,都提示 Undefined offset 而取不到数据。举例描述提问者的问题,假设一个数组 $a,print_r($a) 的输出为
可以看到数组存在索引 1 值为 foo,当使用 $a[1] 或者 $a[‘1’] 访问索引为 1 的元素,都提示 Undefined offset,这就有点让人费解了,下文将讲解这个问题产生的原因,以及如何得到像这样奇怪的一个数组。
首先说明一点,PHP 中数组的 key 可以为整形和字符串,但是包含有合法整型值的字符串会被转换为整型。例如键名 “1” 实际会被储存为 1。来看一个例子,考虑如下代码:
1
2
3
4
5
6
7
|
$a = array(
1 => ‘foo‘,
‘1‘ => ‘bar‘,
‘name‘ => ‘upliu‘,
);
print_r($a);
var_dump($a);
|
将会输出:
可以看到存入到数组里面的 1 为数值索引(注意索引 name 加了引号,说明索引 name 为字符串索引(这不废话嘛,’name’ 肯定是字符串啊)),并且值为 bar 覆盖了先出现的 foo,$a[1] 和 $a[‘1’] 都能正确读取到 bar,且没有任何错误警告提示,说明这个两者都是可用的(笔者在此猜测 $a[‘1’] 实际上完全等效于 $a[1],PHP 数组读取元素的时候会将数值字符串索引转换为数值索引)。
我们先还原一下提问者的问题,看如何生产出那样一个数组。考虑如下代码:
1
2
3
|
$json = ‘{"1":"foo"}‘;
$o = json_decode($json);
var_dump($o);
|
将会输出
这个结果很显而易见,$o 为一个对象,有一个属性为 1,因为该属性并不是合法的 PHP 标识符,因此不能使用箭头的方式访问,我们使用强制类型转换将该对象转换为一个数组:
1
2
|
$a = (array)$o;
print_r($a);
|
将会输出
接下来尝试访问数组 $a 的索引为 1 的元素:
1
2
|
echo $a[1], PHP_EOL;
echo $a[‘1‘], PHP_EOL;
|
上面两条语句均会报错 Undefined offset,这时数组 $a 就是 SO 上那位提问者遇到问题时碰到的数组了,BUG 重现是一件很爽的事啊。
我们来直接将上面代码中的 json 串解析为数组:
1
2
3
4
|
$a2 = json_decode($json, true);
print_r($a2);
echo $a2[1], PHP_EOL;
echo $a2[‘1‘], PHP_EOL;
|
将会输出
一切正常,这个时候问题来了,明明数组 $a 和数组 $a2 使用 print_r 输出一模一样,为什么一个元素可以访问,另一个却不能访问。我们用更强大的 var_dump 看看:
1
2
|
var_dump($a);
var_dump($a2);
|
将会输出
从这个输出我们可以看到数组 $a 和 $a2 的不同,通过将对象强制类型转换得到的数组 $a 拥有一个字符串 ‘1’ 的索引(可以使用 var_dump(array_keys($a))来证实这一点),而我们使用 $a[1] 和 $a[‘1’] 都是访问数组 $a 中索引为 1 的元素,而 $a 并不存在该元素,因此出现错误 Undefined offset。
小结:PHP 默认不会存储整型字符串的索引,会将其转换为数值,在将对象转换为数组的过程中可能引入整型字符串的索引,如果给出索引为整数或整形字符串,访问数组元素都会去获取数组的对应数值索引。
本文实例完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<?php
$json = ‘{"1":"foo"}‘;
$o = json_decode($json);
$a = (array)$o;
print_r($a);
echo $a[1], PHP_EOL;
echo $a[‘1‘], PHP_EOL;
$a2 = json_decode($json, true);
print_r($a2);
echo $a2[1], PHP_EOL;
echo $a2[‘1‘], PHP_EOL;
var_dump($a);
var_dump($a2);
var_dump(array_keys($a));
var_dump(array_keys($a2));
foreach ($a2 as $k => $v) {
var_dump($k);
var_dump($v);
}
foreach ($a as $k => $v) {
var_dump($k);
var_dump($v);
}
|
--本文来源于网络
原文:http://www.cnblogs.com/kl0428/p/6394831.html