This is the 29th day of my participation in the August Wenwen Challenge.More challenges in August

When we started working, it was all XML, but now JSON data formats are the de facto standard for all kinds of applications. Students who have taken up programming in recent years probably have no experience with using XML for data transfer. Of course, times are changing, and JSON is much more convenient and readable than XML. But from a semantic point of view, XML is more expressive.

Without further details, manipulating JSON in PHP is actually quite simple. The most commonly used functions are json_encode() and json_decode(). They have a few caveats and a few fun things to do. Today, we are going to learn more in depth.

JSON encoding

First, we prepare an array for the operations we encode later.

$data = [
    'id'= >1.'name'= >'Test condition'.'cat'= > ['Student &' On the Job ',].'number'= >"123123123".'edu' => [
        [
            'name'= >'< / b > < b > middle school'.'date'= >'2015-2018',], ['name'= >'< / b > < b > university'.'date'= >'2018-2022',]]];Copy the code

Very simple array, in fact, there is nothing special, just data nesting, some Chinese and special symbols. For normal JSON encoding, just use 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":"\u4e2d\u5b66<\/b>","date":"2015-2018"},{"name":"\u5927\u5b 66<\/b>","date":"2018-2022"}]}"
Copy the code

Chinese language processing

Did you find any problems with the above encoded JSON data? Yes, I believe many people will see at a glance, Chinese characters have been converted to the format \uxxxx. By default, the json_encode() function converts these multi-byte characters into Unicode-formatted content. We can solve this problem by simply adding a constant parameter after json_encode() to make Chinese characters appear normally.

$json1 = json_encode($data, JSON_UNESCAPED_UNICODE);
var_dump($json1);
/ / string (179) "{" id" : 1, "name" : "test case", "cat" : [" & students \ "in \" ", "number" : "123123123", "edu" : [{" name ":" < \ / b > < b > middle school ", "date" : "2015-2018"}, {" name ":" < \ / b > < b > university ", "date" : "2018-2022"})} "
Copy the code

Of course, it’s just so boring. Because I once had an interviewer ask me how to solve this kind of problem, and do not use this constant parameter. Can you look beyond the code below and think about your own solutions?

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" : "test case", "cat" : [" & students "In" ", "number", "123123123", "edu" : [{" name ":" < / b > < b > middle school ", "date" : "2015-2018"}, {" name ":" < / b > < b > university ", "date" : "2018-2022"}]}"
Copy the code

In fact, it is a very simple solution, recursively convert all the field contents of the data into urlencode() encoding, and then use json_encode() encoding, and then use urldecode() inverse solution. Isn’t that interesting? In fact, this is a trick of many older programmers, because the JSON_UNESCAPED_UNICODE constant is not available until PHP5.4, before if you want to make the encoded data directly display Chinese, you can only do this operation.

Of course, now is the PHP8 era, has long been no need to operate so troublesome, but also can not rule out some of the interview hall of their own is the old code farmers deliberately out of some such topics. After all, in the actual project development, the use of PHP5.4 version of the system may be really very few (such companies don’t go, the technology update is too slow).

Other parameters

In addition to JSON_UNESCAPED_UNICODE, there are a number of constant parameters that can be used in parallel, meaning that multiple constant parameters can work 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" : "test case", "cat" : [" students \ u0026 In-service \ \ u0022 u0022] ", "number" : 123123123, "edu" : [{" name ":" \ u003Cb \ \ u003C u003E middle school \ \ u003E/b ", "date" : "2015-2018"}, {" name ":" \ u003Cb \ \ u003C u003E university \ \ u003E/b ", "date" : "2018-2022"}}]"
Copy the code

This is a bunch of arguments for special symbols in our data, such as ampersand, <> HTML tags, etc. Of course, there are some constant parameters are not all shown, you can refer to the official manual for instructions.

In addition, json_encode() has a third parameter that represents the level of iteration. For example, the data above is a multidimensional array with three levels, so we need at least three to parse properly. The following code is only given a 1, so it will return false. That is, the code doesn’t work. By default, the value of this parameter is 512.

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

Object and format processing

By default, json_encode() encodes an array based on the type of the data, so if it’s an array, the encoded content is in JSON array format. You can also add a JSON_FORCE_OBJECT that encodes an array as an object.

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

Json_encode () cannot be encoded if there is NAN in the data. In fact, we can add a JSON_PARTIAL_OUTPUT_ON_ERROR to replace some values that cannot be encoded. 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
Copy the code

Object encoding property problems

For objects, jSON-encoded content is like serialization, with only object properties and no methods. After all, JSON is mostly used for data transfer, and methods have no real use for data transfer. Properties, depending on how they are encapsulated, encode only public, that is, public properties.

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

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

As you can see from this test code, the protected property, the private property, and the method are not coded.

JSON decode

For JSON decoding, it’s actually easier because json_decode() doesn’t have as many constants.

var_dump(json_decode($json1));
// object(stdClass)#1 (5) {
// ["id"]=>
// int(1)
// ["name"]=>
// string(12) "Test condition"
// ["cat"]=>
/ /...
/ /...

var_dump(json_decode($json1.true));
// array(5) {
// ["id"]=>
// int(1)
// ["name"]=>
// string(12) "Test condition"
// ["cat"]=>
/ /...
/ /...
Copy the code

So let’s look at the second argument. If this parameter is left out, which is false by default, the decoded data is in object format. If we set this parameter to true, the result will be in array format. This is also a very common function, so I don’t have to explain it.

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

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

Data in this very long numeric format is converted directly to scientific notation if decoded directly by json_decode(). We can use a JSON_BIGINT_AS_STRING constant argument to convert this data to a string when decoded, preserving the original look of the data. Note that the json_decode() function takes four parameters, the third is iteration depth, and the fourth defines the values of the formatted constants, because it has the conversion object as an array. Json_encode () is the reverse of json_encode(), with the iteration depth parameter in front and the format constant parameter in the back.

If the data is wrong, json_decode() returns NULL.

var_dump(json_decode("".true)); // NULL
var_dump(json_decode("{a:1}".true)); // NULL
Copy the code

Error handling

In both of the above paragraphs we demonstrated what happens if there is a problem with the encoded or decoded data, such as json_encode() returning false and json_decode() returning NULL. But what are the specific reasons?

$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"
Copy the code

Json_last_error () and json_last_error_msg() return error messages for JSON operations. In other words, json_encode() and json_decode() normally do not report errors, and if we want to get error information, we need to use these two functions. This is also a lot of novice students did not pay attention to the place, no error message, do not throw exceptions to our development and debugging is actually very unfriendly. Because it’s very possible to look for a long time and not know what the problem is.

After PHP7.3, we added a constant parameter to enable our json_encode() and json_decode() to throw exceptions when the codec error, so that we can quickly locate the problem, now if you run the system is PHP7.3 above the words, It is highly recommended to use this constant parameter to get the system to 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
Copy the code

JSON_THROW_ON_ERROR works on both json_encode() and json_decode(). Again, once the constant parameter is set, we can use try… Catch, catch, 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"
}
Copy the code

JSON serialization interface

In previous articles, we learned to customize the serialization of classes in PHP using the Serializable interface. That is, the Serializable interface lets you customize the serialized formatting content. For JSON, a JsonSerializable interface is also provided to enable me to customize the object format content when ENCODING 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('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}
Copy the code

This is a small example of implementing the jsonSerialize() method in the JsonSerializable interface and returning the content to implement the JSONTest object’s JSON-encoded format specification. Here we simply return the contents of the data, which is not much different from normal json_encode(). Let’s look at it through a more complicated 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 = ['students'];
        }
        if (!$edu) {
            $this->edu = new stdClass;
        }
        $this->number = Student Id: . (!$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.'Test One'), JSON_UNESCAPED_UNICODE));
/ / string (82) "{" id" : 1, "name" : "test a", "cat" : [] "students", "number" : "student number: 14017495", "edu" : {}}"

var_dump(json_encode([new Student(1.'Test One'), new Student(2.'Test Two')], JSON_UNESCAPED_UNICODE));
/ / string (137) "[{" id" : 1, "name" : "test a", "cat" : [] "students", "number" : "student number: 1713936069", "edu" : {}}, [2, "test", [] "students", "student id: 499173036 ", {}]]"
Copy the code

In this example, we do something in jsonSerialize(). If no value is passed, such as null, a default value is given. It then returns an ordinary array with id 2. You can see the format of the second data in the last comment.

This interface is not very interesting, I believe that you may be very familiar with the above jSON_encode () and jSON_decode (), but this interface is estimated that many people really do not contact, is not very interesting.

conclusion

Sure enough, everything is afraid of deep digging. Do not learn do not know, a learn to be surprised, ordinary everyday use so simple JSON operation related functions actually have a lot of good function is we do not know. Of course, the most important or look at the document, understand 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 the version of the friend can use JSON_THROW_ON_ERROR to make errors thrown in time, timely discovery oh!

Test code:

Github.com/zhangyue050…

Reference Documents:

www.php.net/manual/zh/b…