早上看到 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);
}

--本文来源于网络

PHP 中数组获取不到元素的更多相关文章

  1. javascript中DOM获取和设置元素的内容、样式及效果

    getElementById() 根据id获取dom元素 没有找到则返会Null <!DOCTYPE html> <html lang="en"> < ...

  2. Java中数组获取最大值

    最大值获取:从数组的所有元素中找出最大值. 实现思路: 定义变量,保存数组0索引上的元素 遍历数组,获取出数组中的每个元素 将遍历到的元素和保存数组0索引上值的变量进行比较 如果数组元素的值大于了变量 ...

  3. jsp中Java代码中怎么获取jsp页面元素

    举例,页面元素<td><input   value="${sl }" type="text" id="sl" name=& ...

  4. 在Javascript中数组对象(json)里元素相同的操作

    1.数组对象元素相同,分组显示   let arry = [ { expensedate: '2018/09/29', amount: 1, type: '交通费' }, { expensedate: ...

  5. JQuery 数组获取和删除元素

    <script> var target = []; target [0] = "aaa000"; target [1] = "bbb111"; ta ...

  6. vue中mounted中无法获取到dom元素

    一.解决方案: 加上异步setTimeout,延迟获取dom的代码的执行 mounted() { // debugger this.$nextTick(()=> { setTimeout(()= ...

  7. AngularJs在ng-click函数中如何获取代表当前元素的DOM对象

    <!DOCTYPE html> <html> <head> <title></title> <script src="lib ...

  8. js在数组arr中随机获取count数量的元素

    // 在数组arr中随机获取count数量的元素; const getRandomArrayElements = (arr, num) => { // 新建一个数组,将传入的数组复制过来,用于运 ...

  9. LINQ 获取当前数组中出现次数最多的元素

    LINQ 获取当前数组中出现次数最多的元素 1  List<string> a = new List<string>();              a.Add(        ...

随机推荐

  1. 【转载】OLE控件在Direct3D中的渲染方法

    原文:OLE控件在Direct3D中的渲染方法 Windows上的图形绘制是基于GDI的, 而Direct3D并不是, 所以, 要在3D窗口中显示一些Windows中的控件会有很多问题 那么, 有什么 ...

  2. 《Cocos2d-x游戏开发实战精解》学习笔记4--实战一个简单的钢琴

    上一节学习了使用Cocos2d-x播放音乐的方法,但是那种方法一般只适合于播放较大的音乐,而一般比较短小的音乐(如游戏中的打斗.按键音效等)则要通过playEffect来播放.本节使用该方法以及之前学 ...

  3. 食物链 POJ 1182(种类并查集)

    Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到 ...

  4. Minimum Sum of Array(map迭代器)

    You are given an array a consisting of n integers a1, ..., an. In one operation, you can choose 2 el ...

  5. Ubuntu16.04下 protobuf3.4.0 的安装与卸载

    感谢原文作者:https://blog.csdn.net/xiexievv/article/details/47396725 一. 安装 下载protobuf protobuf下载地址:https:/ ...

  6. Numpy and Pandas

    安装 视频链接:https://morvanzhou.github.io/tutorials/data-manipulation/np-pd/ pip install numpy pip instal ...

  7. SSH 框架的心得

    使用SSH框架做完了一个普通网站的前后台项目,成热写点心得,免得以后再入坑.其中使用 Strust2  2.3.33 + Spring 4.3.9 + Hibernate 5.2.10 eclipse ...

  8. spring框架(3)— spring集合类的注入

    1.Car.java package com.eniac.beans; public class Car { private String type; private String factory; ...

  9. Alpha-8

    前言 失心疯病源8 团队代码管理github 站立会议 队名:PMS 530雨勤(组长) 今天完成了那些任务 20:00~23:00 代码整合,已形成可用模块,但还需适应场景局部优化 代码签入gith ...

  10. 给新建的kvm虚拟机创建网络接口

    (一)首先必须创建网卡连接桥接口的启动脚本和停止脚本,其中脚本中的 $1:表示为虚拟机的网卡的右边接口,这两个脚本就是讲虚拟机的网卡的右边接口接在网桥上,实现桥接模型     # 1:/etc/qem ...