Rumah > Artikel > pembangunan bahagian belakang > Mari bercakap tentang fungsi berkaitan JSON dalam PHP
Bagaimana untuk mengendalikan JSON dalam PHP? Artikel ini akan membawa anda untuk mengetahui lebih lanjut tentang fungsi berkaitan JSON dalam PHP dan memperkenalkan beberapa perkara yang perlu anda perhatikan apabila menggunakan fungsi ini. Saya harap ia akan membantu anda!
Dalam era ketika kita mula bekerja, dunia masih dikuasai oleh XML, tetapi kini format data JSON telah menjadi standard de facto untuk penghantaran dalam pelbagai aplikasi. Pelajar yang telah mula mempelajari pengaturcaraan dan pembangunan dalam beberapa tahun kebelakangan ini mungkin tidak pernah didedahkan menggunakan XML untuk penghantaran data. Sudah tentu, masa sentiasa bertambah baik, dan JSON lebih mudah, lebih pantas dan lebih mudah dibaca daripada XML. Tetapi sebenarnya, dari sudut semantik, XML lebih ekspresif.
Tidak banyak yang boleh dikatakan, mengendalikan JSON dalam PHP sebenarnya sangat mudah Dua fungsi yang paling biasa digunakan ialah json_encode() dan json_decode(). Mereka mempunyai beberapa perkara untuk diperhatikan, dan beberapa perkara untuk dinikmati. Hari ini, mari kita kaji dengan mendalam.
Pertama, kami menyediakan tatasusunan untuk operasi pengekodan kami yang seterusnya.
$data = [ 'id' => 1, 'name' => '测试情况', 'cat' => [ '学生 & "在职"', ], 'number' => "123123123", 'edu' => [ [ 'name' => '<b>中学</b>', 'date' => '2015-2018', ], [ 'name' => '<b>大学</b>', 'date' => '2018-2022', ], ], ];
Suatu tatasusunan yang sangat mudah Malah, ia hanya mempunyai sarang data dan beberapa simbol Cina dan khas. Untuk pengekodan JSON biasa, hanya gunakan json_encode() secara langsung.
$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"}]}"
Adakah anda menemui sebarang masalah dengan data JSON yang dikodkan di atas? Betul, saya percaya ramai orang akan melihat sepintas lalu bahawa semua aksara Cina telah ditukar kepada format uxxxx. Ini sebenarnya secara lalai, fungsi json_encode() akan menukar aksara berbilang bait ini kepada kandungan format Unicode. Kita boleh menyelesaikan masalah ini dengan menambah parameter malar terus selepas json_encode(), supaya aksara Cina boleh dipaparkan secara normal.
$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"}]}"
Sudah tentu, ia akan membosankan begitu sahaja. Kerana seorang penemuduga pernah bertanya kepada saya semasa temuduga sama ada saya boleh menyelesaikan masalah seperti ini tanpa menggunakan parameter malar ini. Bolehkah anda berhenti melihat kod di bawah dan fikirkan tentang penyelesaian anda sendiri?
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"}]}"
Malah, ia adalah penyelesaian yang sangat mudah secara rekursif menukar kandungan semua medan dalam data ke dalam pengekodan urlencode(), kemudian gunakan json_encode() untuk mengekod, dan kemudian gunakan urldecode() untuk. menyahkodnya selepas selesai. Menarik tak? Sebenarnya, ini adalah helah kecil ramai pengaturcara lama, kerana pemalar JSON_UNESCAPED_UNICODE hanya tersedia selepas PHP5.4 Sebelum ini, jika anda mahu data yang dikodkan untuk memaparkan bahasa Cina secara langsung, anda hanya boleh melakukannya dengan cara ini.
Sudah tentu, sekarang adalah era PHP8, dan tidak ada keperluan untuk operasi yang menyusahkan seperti itu, bagaimanapun, tidak dapat dinafikan bahawa beberapa dewan temuduga sengaja bertanya soalan sedemikian kerana mereka adalah pengkod yang berpengalaman. Semua orang, sila faham, sudah cukup untuk mengetahui bahawa ini berlaku Lagipun, dalam pembangunan projek sebenar, mungkin terdapat sangat sedikit sistem yang menggunakan versi di bawah PHP5.4 (tidak mengapa untuk tidak pergi ke syarikat sedemikian, kemas kini teknologi adalah. terlalu perlahan).
Selain JSON_UNESCAPED_UNICODE, kami mempunyai banyak parameter malar yang boleh digunakan, dan parameter ini boleh dikendalikan secara selari, iaitu berbilang pemalar boleh digunakan Parameter berkuat kuasa bersama-sama.
$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"}]}"
Sekumpulan parameter ini sebenarnya untuk beberapa simbol khas dalam data kami, seperti & aksara, a8093152e673feb7aba1828c43532094 Sudah tentu, masih terdapat beberapa parameter tetap yang tidak dipaparkan sepenuhnya Anda boleh menyemak sendiri arahan dalam manual rasmi.
Selain itu, json_encode() mempunyai parameter ketiga, yang mewakili tahap lelaran. Sebagai contoh, data yang kami ada di atas ialah tatasusunan berbilang dimensi dengan tiga tahap, jadi kami mesti memberikannya sekurang-kurangnya 3 untuk menghuraikannya secara normal. Dalam kod berikut, kami hanya memberikan 1, jadi kandungan yang dikembalikan adalah palsu. Maksudnya, pengekodan tidak boleh berjaya. Secara lalai, nilai parameter ini ialah 512.
var_dump(json_encode($data, JSON_UNESCAPED_UNICODE, 1)); // bool(false)
Secara lalai, json_encode() akan mengekod mengikut jenis data, jadi jika ia adalah tatasusunan, maka selepas pengekodan Kandungannya ialah format tatasusunan JSON Pada masa ini, kami juga boleh menambah JSON_FORCE_OBJECT untuk membenarkannya mengekod tatasusunan dalam bentuk objek.
$data = []; var_dump(json_encode($data)); // string(2) "[]" var_dump(json_encode($data, JSON_FORCE_OBJECT)); // string(2) "{}"
Kami belajar sebelum ini apabila bercakap tentang fungsi berkaitan matematik bahawa jika terdapat data seperti NAN dalam data, json_encode() tidak boleh mengekodnya, sebenarnya, kami boleh menambah JSON_PARTIAL_OUTPUT_ON_ERROR untuk beberapa data yang tidak boleh dikodkan. nilai diganti. Dalam kod di bawah, kita boleh menggunakannya untuk menggantikan NAN dengan 0.
$data = NAN; var_dump(json_encode($data)); // bool(false) var_dump(json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR)); // 0
Untuk objek, kandungan yang dikodkan JSON adalah sama dengan penyirian Ia hanya akan mempunyai atribut objek dan bukannya Akan ada jalan. Lagipun, penggunaan terbesar JSON adalah untuk penghantaran data, dan kaedah tidak mempunyai kesan praktikal pada penghantaran data. Sifat juga akan berbeza mengikut enkapsulasinya Hanya harta awam, iaitu harta awam, akan dikodkan.
$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_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 以上的话,非常推荐使用这个常量参数让系统来抛出异常。
// 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 是对 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" }
在之前的文章中,我们学习过 使用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('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}
这是一个小的示例,只需要实现 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 = ['学生']; } 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",{}]]"
在这个例子中,我们在 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
作者:硬核项目经理
Pembelajaran yang disyorkan: "Tutorial Video PHP"
Atas ialah kandungan terperinci Mari bercakap tentang fungsi berkaitan JSON dalam PHP. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!