JSON(JavaScript Object Notation)是目前Web开发中数据传输的事实标准之一。它用键值对和数组的组合来组织数据,结构清晰,既方便人阅读,也便于机器解析。尽管名字里带着“JavaScript”,但JSON的设计从一开始就与语言无关——PHP、Python、Java等主流语言都对其提供了原生或库级别的支持。在PHP中,处理JSON的核心就是两个内置函数:json_encode()负责把PHP变量转成JSON字符串,json_decode()负责把JSON字符串还原成PHP能操作的数据结构。
一、JSON数据格式简介
一个典型的JSON结构长这样:
{
"company": {
"name": "创新科技",
"employees": [
{"id": 301, "name": "张明", "role": "后端开发"},
{"id": 302, "name": "李华", "role": "前端开发"},
{"id": 303, "name": "王芳", "role": "UI设计"}
]
}
}
JSON支持的数据类型包括:字符串、数字、布尔值、数组、对象(键值对)、以及null。它的层级嵌套能力使得复杂业务数据也能被清晰地组织起来。在前后端分离的架构里,PHP后端处理完业务逻辑后,把结果数据用json_encode()转成JSON字符串返回给前端,前端JavaScript用JSON.parse()解析后渲染页面——这套流程几乎成了现在Web应用的标配数据交互模式。
二、json_encode():将PHP变量编码为JSON字符串
json_encode()是PHP中将数组、对象、字符串等数据结构转换成JSON格式的核心函数。它处理递归嵌套的能力让复杂数据结构的序列化变得简单高效。
语法结构
string json_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] )
-
$value:要编码的PHP变量,通常是数组或对象。 -
$options:可选,位掩码形式的选项常量,用于控制编码行为,比如JSON_PRETTY_PRINT让输出的JSON格式化换行、JSON_UNESCAPED_UNICODE让中文不转义为\uXXXX。 -
$depth:可选,控制递归嵌套的较大深度,默认512层,一般情况下足够了。 -
返回值:成功时返回JSON字符串,失败时返回
false。
示例1:关联数组转JSON
<?php
$book = array(
"title" => "PHP从入门到实践",
"author" => "陈老师",
"price" => 59.80,
"in_stock" => true
);
echo json_encode($book);
?>
输出结果
{"title":"PHP\u4ece\u5165\u95e8\u5230\u5b9e\u8df5","author":"\u9648\u8001\u5e08","price":59.8,"in_stock":true}
输出里中文被转成了Unicode转义序列,这对机器传输来说没有问题,但调试时很难直接读懂。加上JSON_UNESCAPED_UNICODE选项就能让中文保持可读。
改进写法
<?php
echo json_encode($book, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
?>
输出结果
{
"title": "PHP从入门到实践",
"author": "陈老师",
"price": 59.8,
"in_stock": true
}
JSON_PRETTY_PRINT让JSON按缩进格式化,配合JSON_UNESCAPED_UNICODE,在调试API接口响应时体验会好很多。
示例2:索引数组转JSON
<?php
$colors = array("红色", "蓝色", "绿色", "黄颜色");
echo json_encode($colors, JSON_UNESCAPED_UNICODE);
?>
输出结果
["红色","蓝色","绿色","黄颜色"]
索引数组转成JSON数组,关联数组转成JSON对象,这个映射关系是固定的。
示例3:PHP对象转JSON
<?php
class Product {
public $id = 1001;
public $name = "机械键盘";
public $brand = "知行科技";
}
$product = new Product();
echo json_encode($product, JSON_UNESCAPED_UNICODE);
?>
输出结果
{"id":1001,"name":"机械键盘","brand":"知行科技"}
对象的公共属性(public)会被编码进JSON,私有属性(private)和保护属性(protected)默认不会出现在输出中。如果需要包含私有属性,可以在类里实现JsonSerializable接口来自定义序列化逻辑。
三、为什么需要PHP到JSON的编码
在前后端分离架构普及的今天,PHP后端的一个核心职责就是提供数据接口。前端通过AJAX(通常用fetch或axios)请求PHP脚本,PHP查询数据库、处理业务逻辑后,把结果封装成数组或对象,用json_encode()转成JSON字符串后返回。前端拿到JSON数据,再用JavaScript解析渲染。
一个实际的API响应场景:用户在网页上搜索商品,前端发送GET请求到search.php?keyword=键盘,后端PHP脚本返回如下JSON:
{
"status": "success",
"count": 3,
"products": [
{"id": 201, "name": "机械键盘", "price": 399},
{"id": 202, "name": "薄膜键盘", "price": 89},
{"id": 203, "name": "静电容键盘", "price": 1299}
]
}
前端拿到这个结构后,遍历products数组生成商品列表的HTML。整个过程中JSON承担了数据传输的桥梁角色。
个人经验分享:在写API接口时,我习惯在json_encode()前面加一句header('Content-Type: application/json; charset=utf-8'),强制声明响应的MIME类型。有些浏览器或HTTP客户端会根据Content-Type来决定如何解析响应体,不设这个头可能导致在调试工具里看到的是一串文本而不是解析后的JSON树形结构。返回JSON之前务必确认PHP脚本没有任何多余的echo或var_dump输出,否则和json_encode()的输出混在一起,前端JSON.parse()就会报语法错误。
四、json_decode():将JSON字符串解码为PHP变量
当前端通过POST请求把JSON数据发给后端时(比如用户提交了一个表单,前端把表单数据序列化成JSON放在请求体里),PHP需要把这个JSON字符串还原成自己能操作的数组或对象,这个任务由json_decode()承担。
语法结构
mixed json_decode ( string $json [, bool $assoc = false [, int $depth = 512 [, int $options = 0 ]]] )
-
$json:待解码的JSON字符串。 -
$assoc:设为true时,返回关联数组;默认为false,返回stdClass对象。 -
$depth:递归深度限制,默认512。 -
$options:可选的行为控制位掩码。 -
返回值:成功时返回对应的PHP对象或数组,失败时返回
null。
示例1:将JSON解码为PHP对象(默认行为)
<?php
$json_string = '{"name":"张三","age":25,"city":"广州"}';
$data = json_decode($json_string);
var_dump($data);
?>
输出结果
object(stdClass)#1 (3) {
["name"] => string(6) "张三"
["age"] => int(25)
["city"] => string(6) "广州"
}
解码后得到的是stdClass对象,访问属性使用$data->name这种箭头语法。
示例2:将JSON解码为关联数组
<?php
$json_string = '{"name":"张三","age":25,"city":"广州"}';
$data = json_decode($json_string, true);
var_dump($data);
?>
输出结果
array(3) {
["name"] => string(6) "张三"
["age"] => int(25)
["city"] => string(6) "广州"
}
传入true后返回的就是数组,访问用$data['name']。两种方式都可以,选哪种主要看后续代码的操作习惯——我个人在循环处理数据集时更倾向用数组,在操作单条配置数据时用对象语义更直观。
个人建议:调用json_decode()之后,建议先用json_last_error()检查一下解码过程中是否有问题。如果传进来的JSON字符串格式有误(比如少了引号、多了逗号),json_decode()会静默返回null,不抛异常也不报错,排查起来比较费时间。json_last_error()返回一个错误常量,JSON_ERROR_NONE表示一切正常,其他值对应语法错误、深度超限、控制字符问题等具体情况。
五、编码与解码的完整往返示例
下面用一个完整的例子,演示从创建PHP对象到编码成JSON、再解码回来的完整过程。
<?php
// 定义班级类
class ClassRoom {
public $name;
public $students = array();
}
// 定义学生类
class Student {
public $id;
public $name;
public $score;
}
// 创建学生实例
$stu1 = new Student();
$stu1->id = 1001;
$stu1->name = "小王";
$stu1->score = 92;
$stu2 = new Student();
$stu2->id = 1002;
$stu2->name = "小陈";
$stu2->score = 88;
// 创建班级实例并添加学生
$class = new ClassRoom();
$class->name = "三年级二班";
$class->students = array($stu1, $stu2);
// 编码为JSON
$json_output = json_encode($class, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
echo "编码后的JSON数据:\n" . $json_output . "\n\n";
// 解码回PHP对象
$decoded_class = json_decode($json_output);
echo "解码后的班级名称:" . $decoded_class->name . "\n";
echo "学生列表:\n";
foreach ($decoded_class->students as $student) {
echo " 学号:{$student->id},姓名:{$student->name},成绩:{$student->score}\n";
}
?>
输出结果
编码后的JSON数据:
{
"name": "三年级二班",
"students": [
{
"id": 1001,
"name": "小王",
"score": 92
},
{
"id": 1002,
"name": "小陈",
"score": 88
}
]
}
解码后的班级名称:三年级二班
学生列表:
学号:1001,姓名:小王,成绩:92
学号:1002,姓名:小陈,成绩:88
这个示例展示了JSON在PHP中的典型应用路径:复杂的数据结构先编码为通用的JSON格式进行传输或存储,需要使用时再解码还原。在API开发中,编码环节发生在服务器响应时;解码环节发生在服务器接收到客户端提交的JSON请求体时。
本节课程知识要点
-
json_encode()将PHP变量(数组、对象)转换成JSON字符串,是后端向前端输出数据的核心函数。 -
使用
JSON_UNESCAPED_UNICODE选项可让中文在JSON中保持原样输出,调试时更易读;JSON_PRETTY_PRINT可格式化缩进。 -
json_decode()将JSON字符串还原为PHP变量,第二个参数设为true返回关联数组,默认返回stdClass对象。 -
调用
json_decode()后,建议用json_last_error()检查解码是否成功,避免因JSON格式错误导致的静默失败。 -
输出JSON响应前设置
Content-Type: application/json头,确保客户端正确识别响应格式。 -
JSON序列化时,对象的
private和protected属性默认被忽略,如需包含可通过实现JsonSerializable接口来自定义序列化行为。 -
在前后端数据交互中,JSON承担着“通用数据格式”的桥梁角色,理解编码与解码的完整闭环,是构建稳定API接口的基本功。
JSON在PHP中的处理围绕着json_encode()和json_decode()两个函数展开,看似简单,但在项目里,处理中文字符集、嵌套层数控制、错误调试、以及私有属性的序列化需求,都会给开发者带来一些值得关注的细节。把这些基础操作练熟,无论是开发RESTful API、对接第三方接口,还是做配置文件的数据持久化,都能游刃有余。