目录
JSON 编码
中文处理
其它参数
对象及格式处理
对象编码的属性问题
JSON 解码
错误处理
JSON 序列化接口
总结
首页 后端开发 php教程 聊聊PHP中与JSON相关的函数

聊聊PHP中与JSON相关的函数

Sep 07, 2021 pm 07:41 PM
json函数 php

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

聊聊PHP中与JSON相关的函数

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

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

JSON 编码

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

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

非常简单地数组,其实也没有什么特别的东西,只是有数据的嵌套,有一些中文和特殊符号而已。对于普通的 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(&#39;{"a":1321231231231231231231231231231231231231231231231231231231231231231231233}&#39;, true));
// array(1) {
//     ["a"]=>
//     float(1.3212312312312E+72)
//   }

var_dump(json_decode(&#39;{"a":1321231231231231231231231231231231231231231231231231231231231231231231233}&#39;, 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 以上的话,非常推荐使用这个常量参数让系统来抛出异常。

// php7.3
var_dump(json_encode($data, JSON_THROW_ON_ERROR));
// Fatal error: Uncaught JsonException: Inf and NaN cannot be JSON encoded

var_dump(json_decode(&#39;&#39;, true, 512, JSON_THROW_ON_ERROR));
// PHP Fatal error:  Uncaught JsonException: Syntax error
登录后复制

JSON_THROW_ON_ERROR 是对 json_encode() 和 json_decode() 都起效的。同样,只要设定了这个常量参数,我们就可以使用 try...catch 来进行捕获了。

try {
    var_dump(json_encode($data, JSON_THROW_ON_ERROR));
} catch (JsonException $e) {
    var_dump($e->getMessage()); // string(34) "Inf and NaN cannot be JSON encoded"
}
登录后复制

JSON 序列化接口

在之前的文章中,我们学习过 使用Serializable接口来自定义PHP中类的序列化 。也就是说,通过 Serializable 接口我们可以自定义序列化的格式内容。而对于 JSON 来说,同样也提供了一个 JsonSerializable 接口来实现我自定义 JSON 编码时的对象格式内容。

class jsontest implements JsonSerializable
{
    public function __construct($value)
    {$this->value = $value;}
    public function jsonSerialize()
    {return $this->value;}
}

print "Null -> " . json_encode(new jsontest(null)) . "\n";
print "Array -> " . json_encode(new jsontest(array(1, 2, 3))) . "\n";
print "Assoc. -> " . json_encode(new jsontest(array(&#39;a&#39; => 1, &#39;b&#39; => 3, &#39;c&#39; => 4))) . "\n";
print "Int -> " . json_encode(new jsontest(5)) . "\n";
print "String -> " . json_encode(new jsontest(&#39;Hello, World!&#39;)) . "\n";
print "Object -> " . json_encode(new jsontest((object) array(&#39;a&#39; => 1, &#39;b&#39; => 3, &#39;c&#39; => 4))) . "\n";
// Null -> null
// Array -> [1,2,3]
// Assoc. -> {"a":1,"b":3,"c":4}
// Int -> 5
// String -> "Hello, World!"
// Object -> {"a":1,"b":3,"c":4}
登录后复制

这是一个小的示例,只需要实现 JsonSerializable 接口中的 jsonSerialize() 方法并返回内容就可以实现这个 jsontest 对象的 JSON 编码格式的指定。这里我们只是简单地返回了数据的内容,其实和普通的 json_encode() 没什么太大的区别。下面我们通过一个复杂的例子看一下。

class Student implements JsonSerializable
{
    private $id;
    private $name;
    private $cat;
    private $number;
    private $edu;
    public function __construct($id, $name, $cat = null, $number = null, $edu = null)
    {
        $this->id = $id;
        $this->name = $name;
        $this->cat = $cat;
        $this->number = $number;
        $this->edu = $edu;

    }
    public function jsonSerialize()
    {
        if (!$cat) {
            $this->cat = [&#39;学生&#39;];
        }
        if (!$edu) {
            $this->edu = new stdClass;
        }
        $this->number = &#39;学号:&#39; . (!$number ? mt_rand() : $number);
        if ($this->id == 2) {
            return [
                $this->id,
                $this->name,
                $this->cat,
                $this->number,
                $this->edu,
            ];
        }
        return [
            &#39;id&#39; => $this->id,
            &#39;name&#39; => $this->name,
            &#39;cat&#39; => $this->cat,
            &#39;number&#39; => $this->number,
            &#39;edu&#39; => $this->edu,
        ];
    }
}

var_dump(json_encode(new Student(1, &#39;测试一&#39;), JSON_UNESCAPED_UNICODE));
// string(82) "{"id":1,"name":"测试一","cat":["学生"],"number":"学号:14017495","edu":{}}"

var_dump(json_encode([new Student(1, &#39;测试一&#39;), new Student(2, &#39;测试二&#39;)], JSON_UNESCAPED_UNICODE));
// string(137) "[{"id":1,"name":"测试一","cat":["学生"],"number":"学号:1713936069","edu":{}},[2,"测试二",["学生"],"学号:499173036",{}]]"
登录后复制

在这个例子中,我们在 jsonSerialize() 做了一些操作。如果数据没有传值,比如为 null 的情况下就给一个默认值。然后在 id 为 2 的情况下返回一个普通数组。大家可以看到最后一段注释中的第二条数据的格式。

这个接口是不是很有意思,相信大家可能对上面的 json_encode() 和 json_decode() 非常熟悉了,但这个接口估计不少人真的是没接触过,是不是非常有意思。

总结

果然,什么事情都怕深挖。不学不知道,一学吓一跳,平常天天用得这么简单的 JSON 操作的相关函数其实还有很多好用的功能是我们不知道的。当然,最主要的还是看看文档,弄明白并且记住一些非常好用的常量参数,另外,抛出异常的功能也是这篇文章的重点内容,建议版本达到的朋友最好都能使用 JSON_THROW_ON_ERROR 来让错误及时抛出,及时发现哦!

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202012/source/11.深入学习PHP中的JSON相关函数.php

参考文档:

https://www.php.net/manual/zh/book.json.php

本文转载自:https://juejin.cn/post/7001652041814638600

作者:硬核项目经理

推荐学习:《PHP视频教程

以上是聊聊PHP中与JSON相关的函数的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 带来了多项新功能、安全性改进和性能改进,同时弃用和删除了大量功能。 本指南介绍了如何在 Ubuntu、Debian 或其衍生版本上安装 PHP 8.4 或升级到 PHP 8.4

如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也称为 VS Code,是一个免费的源代码编辑器 - 或集成开发环境 (IDE) - 可用于所有主要操作系统。 VS Code 拥有针对多种编程语言的大量扩展,可以轻松编写

我后悔之前不知道的 7 个 PHP 函数 我后悔之前不知道的 7 个 PHP 函数 Nov 13, 2024 am 09:42 AM

如果您是一位经验丰富的 PHP 开发人员,您可能会感觉您已经在那里并且已经完成了。您已经开发了大量的应用程序,调试了数百万行代码,并调整了一堆脚本来实现操作

您如何在PHP中解析和处理HTML/XML? 您如何在PHP中解析和处理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示了如何使用PHP有效地处理XML文档。 XML(可扩展的标记语言)是一种用于人类可读性和机器解析的多功能文本标记语言。它通常用于数据存储

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

php程序在字符串中计数元音 php程序在字符串中计数元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符组成的序列,包括字母、数字和符号。本教程将学习如何使用不同的方法在PHP中计算给定字符串中元音的数量。英语中的元音是a、e、i、o、u,它们可以是大写或小写。 什么是元音? 元音是代表特定语音的字母字符。英语中共有五个元音,包括大写和小写: a, e, i, o, u 示例 1 输入:字符串 = "Tutorialspoint" 输出:6 解释 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。总共有 6 个元

解释PHP中的晚期静态绑定(静态::)。 解释PHP中的晚期静态绑定(静态::)。 Apr 03, 2025 am 12:04 AM

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。

什么是PHP魔术方法(__ -construct,__destruct,__call,__get,__ set等)并提供用例? 什么是PHP魔术方法(__ -construct,__destruct,__call,__get,__ set等)并提供用例? Apr 03, 2025 am 12:03 AM

PHP的魔法方法有哪些?PHP的魔法方法包括:1.\_\_construct,用于初始化对象;2.\_\_destruct,用于清理资源;3.\_\_call,处理不存在的方法调用;4.\_\_get,实现动态属性访问;5.\_\_set,实现动态属性设置。这些方法在特定情况下自动调用,提升代码的灵活性和效率。

See all articles