In-depth study of JSON related functions in PHP
In the era when we just went to work, XML was still the world, but now the JSON data format is the de facto standard for transmission in various applications. In recent years, students who have started to learn programming and development may not have been exposed to the use of XML for data transmission. Of course, the times are always advancing. Compared with XML, JSON is more convenient, faster, and more readable. But in fact, from a semantic point of view, XML has a stronger form of expression.
Without further ado, operating JSON in PHP is actually very simple. The two most commonly used functions are json_encode() and json_decode(). They have some points to pay attention to, but also some interesting points. Today, we will learn more deeply.
JSON encoding
First, we prepare an array for the operation of our subsequent coding.
$data = [
'id' => 1,
'name' => '测试情况',
'cat' => [
'学生 & "在职"',
],
'number' => "123123123",
'edu' => [
[
'name' => '<b>中学</b>',
'date' => '2015-2018',
],
[
'name' => '<b>大学</b>',
'date' => '2018-2022',
],
],
];
Very simple array, in fact, there is nothing special, just the nesting of data, there are some Chinese and special symbols. For ordinary JSON encoding, just use json_encode() directly.
$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"}]}"
Chinese processing
Have you found any problems with the encoded JSON data above? That's right, I believe many people will see at a glance that all Chinese characters are converted into \uxxxx format. This is actually by default, the json_encode() function will convert these multi-byte characters into Unicode format content. We can solve this problem by adding a constant parameter directly after json_encode(), so that Chinese characters can be displayed normally.
$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"}]}"
Of course, it's just so boring. Because I was once asked by an interviewer during an interview if I can solve this problem without using this constant parameter. Can you think about what solutions you have without looking at the code below?
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"}]}"
In fact, it is a very simple solution. Recursively convert all the field contents in the data into urlencode() encoding, then use json_encode() encoding, and then use urldecode() to reverse the solution after completion. Isn't it interesting? In fact, this is a trick of many old programmers, because the JSON_UNESCAPED_UNICODE constant was only available after PHP5.4. Before, if you want the encoded data to display Chinese directly, you can only do this.
Of course, it is now in the era of PHP8, and there is no need for such a troublesome operation, but it cannot be ruled out that some interview halls deliberately ask such questions because they are old code farmers. As you understand, it’s okay to know that this is the case. After all, in actual project development, there may be very few systems using versions below PHP5.4 (whether such a company does not go, the technology update is too slow) .
Other parameters
In addition to JSON_UNESCAPED_UNICODE, we also have many constant parameters that can be used, and this parameter can be operated in parallel, that is, multiple constant parameters can take effect together.
$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"}]}"
This bunch of parameters are actually for some special symbols in our data, such as ampersands, <> HTML tags, etc. Of course, there are still some constant parameters that are not all shown. You can refer to the instructions in the official manual for yourself.
In addition, json_encode() has a third parameter, which represents the level of iteration. For example, the data above is a multi-dimensional array, which has three layers, so we have to give at least 3 to parse it normally. In the code below, we just give a 1, so the returned content is false. That is, it cannot be successfully encoded. By default, the value of this parameter is 512.
var_dump(json_encode($data, JSON_UNESCAPED_UNICODE, 1)); // bool(false)
Object and format processing
By default, json_encode() will encode according to the type of data, so if it is an array, then the content after encoding is the JSON array format. At this time, we can also add a JSON_FORCE_OBJECT to make it an array of objects Form to be coded.
$data = [];
var_dump(json_encode($data)); // string(2) "[]"
var_dump(json_encode($data, JSON_FORCE_OBJECT)); // string(2) "{}"
We learned before when we talked about math related functions. If there is NAN in the data, json_encode() cannot be encoded. In fact, we can add a JSON_PARTIAL_OUTPUT_ON_ERROR to replace some unencoded values. In the following code, we can use it to replace NAN with 0.
$data = NAN;
var_dump(json_encode($data)); // bool(false)
var_dump(json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR)); // 0
The problem of the attributes of the object code
For objects, the JSON-encoded content is the same as serialization, with only object properties but no methods. After all, the biggest use of JSON is for data transmission, and the method has no practical effect on data transmission. The attributes will also be different according to its encapsulation, only the public, that is, public attributes will be encoded.
$data = new class
{
private $a = 1;
protected $b = 2;
public $c = 3;
public function x(){
}
};
var_dump(json_encode($data)); // string(7) "{"c":3}"
As can be seen from this test code, the protected, private attributes and that method will not be encoded.
JSON decoding
For JSON decoding, it is actually easier, because there are not so many constant parameters in 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"]=>
// ……
// ……
First of all, let's take a look at its second parameter. The function of this parameter can actually be seen from the code. If this parameter is not filled in, that is, its value is false by default, then the decoded data is in object format. And if we set this parameter to true, then the decoded result will be in array format. This is also a very commonly used function, so I won't explain it much.
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"
// }
For this very long digital format data, if it is directly decoded by json_decode(), it will be directly converted into scientific notation. We can directly use a JSON_BIGINT_AS_STRING constant parameter to directly convert this data into a string when decoding, which in fact retains the original appearance of the data. Note that the parameter of the json_decode() function here has four parameters because there is a parameter that converts the object into an array. The third parameter is the iteration depth, and the fourth is to define these formatting constant values. And it is the reverse of json_encode(), the iteration depth parameter is first, and the format constant parameter is the back. You must pay attention here!
If the data is wrong, then json_decode() will return NULL.
var_dump(json_decode("", true)); // NULL
var_dump(json_decode("{a:1}", true)); // NULL
Error handling
In the above two pieces of code, we have demonstrated what happens if there is a problem with the encoded or decoded data. For example, json_encode() will return false and json_decode() will return NULL. But the specific reason?
$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"
That's right, json_last_error() and json_last_error_msg() return error information during JSON operations. In other words, json_encode() and json_decode() will not report errors under normal circumstances. If we want to get error information, we have to use these two functions to get it. This is also something that many novice students have not paid attention to. There is no error message and no exception is thrown. It is actually very unfriendly to our development and debugging. Because it is very likely that after searching for a long time, I don't know where the problem is.
After PHP7.3, a new constant parameter has been added, which allows our json_encode() and json_decode() to throw exceptions when encoding and decoding errors, so that we can quickly locate the problem. Now if your system is running If the environment is PHP7.3 or higher, it is highly recommended to use this constant parameter to let the system throw an exception.
// 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('', true, 512, JSON_THROW_ON_ERROR));
// PHP Fatal error: Uncaught JsonException: Syntax error
JSON_THROW_ON_ERROR is effective for both json_encode() and json_decode(). Similarly, as long as this constant parameter is set, we can use try...catch to capture.
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 serialization interface
In the previous article, we learned that uses the Serializable interface to customize the serialization of classes in PHP . In other words, we can customize the serialized format content through the Serializable interface. For JSON, it also provides a JsonSerializable interface to implement the object format content when I customize JSON encoding.
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('a' => 1, 'b' => 3, 'c' => 4))) . "\n";
print "Int -> " . json_encode(new jsontest(5)) . "\n";
print "String -> " . json_encode(new jsontest('Hello, World!')) . "\n";
print "Object -> " . json_encode(new jsontest((object) array('a' => 1, 'b' => 3, 'c' => 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}
This is a small example. You only need to implement the jsonSerialize() method in the JsonSerializable interface and return the content to specify the JSON encoding format of this jsontest object. Here we simply return the content of the data, which is actually not much different from ordinary json_encode(). Let's take a look through a complex example.
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 = ['学生'];
}
if (!$edu) {
$this->edu = new stdClass;
}
$this->number = '学号:' . (!$number ? mt_rand() : $number);
if ($this->id == 2) {
return [
$this->id,
$this->name,
$this->cat,
$this->number,
$this->edu,
];
}
return [
'id' => $this->id,
'name' => $this->name,
'cat' => $this->cat,
'number' => $this->number,
'edu' => $this->edu,
];
}
}
var_dump(json_encode(new Student(1, '测试一'), JSON_UNESCAPED_UNICODE));
// string(82) "{"id":1,"name":"测试一","cat":["学生"],"number":"学号:14017495","edu":{}}"
var_dump(json_encode([new Student(1, '测试一'), new Student(2, '测试二')], JSON_UNESCAPED_UNICODE));
// string(137) "[{"id":1,"name":"测试一","cat":["学生"],"number":"学号:1713936069","edu":{}},[2,"测试二",["学生"],"学号:499173036",{}]]"
In this example, we did some operations in jsonSerialize(). If the data has no value, such as null, a default value is given. Then return an ordinary array if the id is 2. You can see the format of the second piece of data in the last comment.
Is this interface very interesting? I believe you may be very familiar with the above json_encode() and json_decode(), but it is estimated that many people have never touched this interface. Is it very interesting?
Summarize
Sure enough, I was afraid of digging deep into everything. If you don’t learn it, you’ll be shocked. We don’t know that there are actually many useful functions related to JSON operations that are usually used every day. Of course, the most important thing is to look at the documentation, figure out and remember some very useful constant parameters. In addition, the function of throwing exceptions is also the focus of this article. It is recommended that friends who reach the version can use JSON_THROW_ON_ERROR. Let the error be thrown out in time, and find out in time!
Test code:
Reference documents:
https://www.php.net/manual/zh/book.json.php
Searchable on their respective media platforms [Hardcore Project Manager]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。