PHP中要怎么操作JSON?本篇文章带大家深入学习一下PHP中与JSON相关的函数,介绍一下使用这些函数需要注意的一些地方,希望对大家有所帮助!

php入门到就业线上直播课:进入学习
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API调试工具:点击使用

在我们当年刚刚上班的那个年代,还全是 XML 的天下,但现在 JSON 数据格式已经是各种应用传输的事实标准了。最近几年开始学习编程开发的同学可能都完全没有接触过使用 XML 来进行数据传输。当然,时代是一直在进步的,JSON 相比 XML 来说,更加地方便快捷,可读性更高。但其实从语义的角度来说,XML 的表现形式更强。

话不多说,在 PHP 中操作 JSON 其实非常简单,大家最常用的无非也就是 json_encode() 和 json_decode() 这两个函数。它们有一些需要注意的地方,也有一些好玩的地方。今天,我们就来深入地再学习一下。

JSON 编码

首先,我们准备一个数组,用于我们后面编码的操作。

$data = [
    'id' => 1,
    'name' => '测试情况',
    'cat' => [
        '学生 & "在职"',
    ],
    'number' => "123123123",
    'edu' => [
        [
            'name' => '<b>中学</b>',
            'date' => '2015-2018',
        ],
        [
            'name' => '<b>大学</b>',
            'date' => '2018-2022',
        ],
    ],
];

非常简单地数组,其实也没有什么特别的东西,只是有数据的嵌套,有一些中文和特殊符号而已。对于普通的 JSON 编码来说,直接使用 json_encode() 就可以了。

$json1 = json_encode($data);
var_dump($json1);
// string(215) "{"id":1,"name":"\u6d4b\u8bd5\u60c5\u51b5","cat":["\u5b66\u751f & \"\u5728\u804c\""],"number":"123123123","edu":[{"name":"<b>\u4e2d\u5b66<\/b>","date":"2015-2018"},{"name":"<b>\u5927\u5b66<\/b>","date":"2018-2022"}]}"

中文处理

上面编码后的 JSON 数据发现了什么问题没?没错,相信不少人一眼就会看出,中文字符全被转换成了 \uxxxx 这种格式。这其实是在默认情况下,json_encode() 函数都会将这些多字节字符转换成 Unicode 格式的内容。我们直接在 json_encode() 后面增加一个常量参数就可以解决这个问题,让中文字符正常地显示出来。

$json1 = json_encode($data, JSON_UNESCAPED_UNICODE);
var_dump($json1);
// string(179) "{"id":1,"name":"测试情况","cat":["学生 & \"在职\""],"number":"123123123","edu":[{"name":"<b>中学<\/b>","date":"2015-2018"},{"name":"<b>大学<\/b>","date":"2018-2022"}]}"

当然,只是这样就太没意思了。因为我曾经在面试的时候就有一位面试官问过我,如果解决这种问题,而且不用这个常量参数。大家可以先不看下面的代码,思考一下自己有什么解决方案吗?

function t($data)
{
    foreach ($data as $k => $d) {
        if (is_object($d)) {
            $d = (array) $d;
        }
        if (is_array($d)) {
            $data[$k] = t($d);
        } else {
            $data[$k] = urlencode($d);
        }
    }
    return $data;
}
$newData = t($data);

$json1 = json_encode($newData);
var_dump(urldecode($json1));
// string(177) "{"id":"1","name":"测试情况","cat":["学生 & "在职""],"number":"123123123","edu":[{"name":"<b>中学</b>","date":"2015-2018"},{"name":"<b>大学</b>","date":"2018-2022"}]}"

其实就是一个很简单地解决方案,递归地将数据中所有字段内容转换成 urlencode() 编码,然后再使用 json_encode() 编码,完成之后再使用 urldecode() 反解出来。是不是有点意思?其实这是不少老程序员的一个小技巧,因为 JSON_UNESCAPED_UNICODE 这个常量是在 PHP5.4 之后才有的,之前的话如果想让编码后的数据直接显示中文,就只能这样操作了。

当然,现在已经是 PHP8 时代了,早就已经不需要这么麻烦地操作了,不过也不能排除有些面试馆仗着自己是老码农故意出些这样的题目。大家了解下,知道有这么回事就可以了,毕竟在实际的项目开发中,使用 PHP5.4 以下版本的系统可能还真是非常少了(这样的公司不去也罢,技术更新得太慢了)。

其它参数

除了 JSON_UNESCAPED_UNICODE 之外,我们还有许多的常量参数可以使用,而且这个参数是可以并行操作的,也就是可以多个常量参数共同生效。

$json1 = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_NUMERIC_CHECK | JSON_HEX_QUOT);
var_dump($json1);
// string(230) "{"id":1,"name":"测试情况","cat":["学生 \u0026 \u0022在职\u0022"],"number":123123123,"edu":[{"name":"\u003Cb\u003E中学\u003C\/b\u003E","date":"2015-2018"},{"name":"\u003Cb\u003E大学\u003C\/b\u003E","date":"2018-2022"}]}"

这一堆参数其实是针对的我们数据中的一些特殊符号,比如说 & 符、<> HTML 标签等。当然,还有一些常量参数没有全部展示出来,大家可以自己查阅官方手册中的说明。

另外,json_encode() 还有第三个参数,代表的是迭代的层级。比如我们上面的这个数据是多维数组,它有三层,所以我们至少要给到 3 才能正常地解析。下面代码我们只是给了一个 1 ,所以返回的内容就是 false 。也就是无法编码成功。默认情况下,这个参数的值是 512 。

var_dump(json_encode($data, JSON_UNESCAPED_UNICODE, 1)); // bool(false)

对象及格式处理

默认情况下,json_encode() 会根据数据的类型进行编码,所以如果是数组的话,那么它编码之后的内容就是 JSON 的数组格式,这时我们也可以添加一个 JSON_FORCE_OBJECT ,让它将一个数组以对象的形式进行编码。

$data = [];
var_dump(json_encode($data)); // string(2) "[]"
var_dump(json_encode($data, JSON_FORCE_OBJECT)); // string(2) "{}"

之前在讲数学相关函数的时候我们学习过,如果数据中有 NAN 这种数据的话,json_encode() 是无法编码的,其实我们可以添加一个 JSON_PARTIAL_OUTPUT_ON_ERROR ,对一些不可编码的值进行替换。下面的代码中,我们就可以使用它让 NAN 替换成 0 。

$data = NAN;
var_dump(json_encode($data)); // bool(false)
var_dump(json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR)); // 0

对象编码的属性问题

对于对象来说,JSON 编码后的内容就和序列化一样,只会有对象的属性而不会有方法。毕竟 JSON 最大的用处就是用于数据传输的,方法对于数据传输来说没有什么实际的作用。而属性也会根据它的封装情况有所不同,只会编码公共的,也就是 public 的属性。

$data = new class
{
    private $a = 1;
    protected $b = 2;
    public $c = 3;

    public function x(){
        
    }
};
var_dump(json_encode($data)); // string(7) "{"c":3}"

从这段测试代码中可以看出,protected 、 private 属性以及那个方法都不会被编码。

JSON 解码

对于 JSON 解码来说,其实更简单一些,因为 json_decode() 的常量参数没有那么多。

var_dump(json_decode($json1));
// object(stdClass)#1 (5) {
//     ["id"]=>
//     int(1)
//     ["name"]=>
//     string(12) "测试情况"
//     ["cat"]=>
// ……
// ……

var_dump(json_decode($json1, true));
// array(5) {
//     ["id"]=>
//     int(1)
//     ["name"]=>
//     string(12) "测试情况"
//     ["cat"]=>
// ……
// ……

首先还是看下它的第二个参数。这个参数的作用其实从代码中就可以看出来,如果不填这个参数,也就是默认情况下它的值是 false ,那么解码出来的数据是对象格式的。而我们将这具参数设置为 true 的话,那么解码后的结果就会是数组格式的。这个也是大家非常常用的功能,就不多做解释了。

var_dump(json_decode('{"a":1321231231231231231231231231231231231231231231231231231231231231231231233}', true));
// array(1) {
//     ["a"]=>
//     float(1.3212312312312E+72)
//   }

var_dump(json_decode('{"a":1321231231231231231231231231231231231231231231231231231231231231231231233}', true, 512, JSON_BIGINT_AS_STRING));
// array(1) {
//     ["a"]=>
//     string(73) "1321231231231231231231231231231231231231231231231231231231231231231231233"
//   }

对于这种非常长的数字格式的数据来说,如果直接 json_decode() 解码的话,它会直接转换成 科学计数法 。我们可以直接使用一个 JSON_BIGINT_AS_STRING 常量参数,将这种数据在解码的时候直接转换成字符串,其实也就是保留了数据的原始样貌。注意,这里 json_decode() 函数的参数因为有那个转换对象为数组的参数存在,所以它有四个参数,第三个参数是迭代深度,第四个就是定义这些格式化常量值的。而且它和 json_encode() 是反过来的,迭代深度参数在前,格式常量参数在后面,这里一定要注意哦!

如果数据是错误的,那么 json_decode() 会返回 NULL 。

var_dump(json_decode("", true)); // NULL
var_dump(json_decode("{a:1}", true)); // NULL

错误处理

上面两段代码中我们都演示了如果编码或解码的数据有问题会出现什么情况,比如 json_encode() 会返回 false ,json_decode() 会返回 NULL 。但是具体的原因呢?

$data = NAN;
var_dump(json_encode($data)); // bool(false)
var_dump(json_last_error()); // int(7)
var_dump(json_last_error_msg()); // string(34) "Inf and NaN cannot be JSON encoded"

没错,json_last_error() 和 json_last_error_msg() 就是返回 JSON 操作时的错误信息的。也就是说,json_encode() 和 json_decode() 在正常情况下是不会报错的,我们如果要获得错误信息,就得使用这两个函数来获取。这一点也是不少新手小同学没有注意过的地方,没错误信息,不抛出异常问题对我们的开发调试其实是非常不友好的。因为很可能找了半天都不知道问题出在哪里。

在 PHP7.3 之后,新增加了一个常量参数,可以让我们的 json_encode() 和 json_decode() 在编解码错误的时候抛出异常,这样我们就可以快速地定位问题了,现在如果大家的系统运行环境是 PHP7.3 以上的话,非常

聊聊PHP中与JSON相关的函数