Maison > Article > développement back-end > Parlons des fonctions liées à JSON en PHP
Comment faire fonctionner JSON en PHP ? Cet article vous amènera à en savoir plus sur les fonctions liées à JSON dans PHP et à présenter certaines choses auxquelles vous devez faire attention lors de l'utilisation de ces fonctions. J'espère qu'il vous sera utile !
À l'époque où nous avons commencé à travailler, le monde était encore dominé par XML, mais aujourd'hui, le format de données JSON est devenu le standard de facto pour la transmission dans diverses applications. Les étudiants qui ont commencé à apprendre la programmation et le développement ces dernières années n'ont peut-être jamais été exposés à l'utilisation de XML pour la transmission de données. Bien entendu, les temps s’améliorent constamment. Comparé à XML, JSON est plus pratique, plus rapide et plus lisible. Mais en réalité, d’un point de vue sémantique, XML est plus expressif.
Sans plus tard, exploiter JSON en PHP est en fait très simple. Les deux fonctions les plus couramment utilisées sont json_encode() et json_decode(). Ils ont certaines choses à surveiller et d’autres choses à apprécier. Aujourd’hui, étudions-le en profondeur.
Tout d'abord, nous préparons un tableau pour nos opérations d'encodage ultérieures.
$data = [ 'id' => 1, 'name' => '测试情况', 'cat' => [ '学生 & "在职"', ], 'number' => "123123123", 'edu' => [ [ 'name' => '<b>中学</b>', 'date' => '2015-2018', ], [ 'name' => '<b>大学</b>', 'date' => '2018-2022', ], ], ];
Un tableau très simple. En fait, il n'y a rien de spécial. Il contient juste une imbrication de données et quelques symboles chinois et spéciaux. Pour un encodage JSON ordinaire, utilisez simplement json_encode() directement.
$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"}]}"
Avez-vous rencontré des problèmes avec les données JSON codées ci-dessus ? C'est vrai, je pense que beaucoup de gens verront d'un coup d'œil que tous les caractères chinois ont été convertis au format uxxxx. C'est en fait par défaut que la fonction json_encode() convertira ces caractères multi-octets en contenu au format Unicode. Nous pouvons résoudre ce problème en ajoutant un paramètre constant directement après json_encode(), afin que les caractères chinois puissent être affichés normalement.
$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"}]}"
Bien sûr, ce serait ennuyeux juste comme ça. Parce qu'un intervieweur m'a demandé un jour lors d'un entretien si je pouvais résoudre ce problème sans utiliser ce paramètre constant. Pouvez-vous s'il vous plaît arrêter de regarder le code ci-dessous et réfléchir à vos propres 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":"测试情况","cat":["学生 & "在职""],"number":"123123123","edu":[{"name":"<b>中学</b>","date":"2015-2018"},{"name":"<b>大学</b>","date":"2018-2022"}]}"
est en fait une solution très simple, convertissez récursivement tout le contenu des champs dans les données en encodage urlencode(), puis utilisez json_encode() pour encoder, puis utilisez urldecode() pour le décoder une fois terminé. N'est-ce pas intéressant ? En fait, c'est une petite astuce de nombreux anciens programmeurs, car la constante JSON_UNESCAPED_UNICODE n'était disponible qu'après PHP5.4. Avant, si vous vouliez que les données codées affichent directement le chinois, vous ne pouviez le faire que de cette façon.
Bien sûr, nous sommes maintenant à l'ère PHP8, et des opérations aussi fastidieuses ne sont pas nécessaires. Cependant, il ne peut être exclu que certaines salles d'entretien posent délibérément de telles questions parce qu'elles sont des codeurs expérimentés. Tout le monde, comprenez, il suffit de savoir que c'est le cas. Après tout, dans le développement réel d'un projet, il peut y avoir très peu de systèmes utilisant des versions inférieures à PHP5.4 (c'est normal de ne pas s'adresser à une telle entreprise, la mise à jour technologique est importante). trop lent) .
En plus de JSON_UNESCAPED_UNICODE, nous avons également de nombreux paramètres constants qui peuvent être utilisés, et ce paramètre peut être utilisé en parallèle, c'est-à-dire que plusieurs paramètres constants peuvent prendre effet ensemble.
$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"}]}"
Cet ensemble de paramètres concerne en fait certains symboles spéciaux dans nos données, tels que les caractères &, les balises HTML a8093152e673feb7aba1828c43532094 Bien entendu, certains paramètres constants ne sont pas tous affichés. Vous pouvez vérifier par vous-même les instructions du manuel officiel.
De plus, json_encode() possède un troisième paramètre, qui représente le niveau d'itération. Par exemple, les données que nous avons ci-dessus sont un tableau multidimensionnel à trois niveaux, nous devons donc lui en donner au moins 3 pour l'analyser normalement. Dans le code suivant, nous venons de donner un 1, donc le contenu renvoyé est faux. Autrement dit, l’encodage ne peut pas réussir. Par défaut, la valeur de ce paramètre est 512.
var_dump(json_encode($data, JSON_UNESCAPED_UNICODE, 1)); // bool(false)
Par défaut, json_encode() encodera en fonction du type de données, donc s'il s'agit d'un tableau, alors le contenu encodé est le format de tableau de JSON. À ce stade, nous pouvons également. ajoutez un JSON_FORCE_OBJECT qui code un tableau en tant qu'objet.
$data = []; var_dump(json_encode($data)); // string(2) "[]" var_dump(json_encode($data, JSON_FORCE_OBJECT)); // string(2) "{}"
Nous avons déjà appris en parlant de fonctions liées aux mathématiques que s'il y a des données comme NAN dans les données, json_encode() ne peut pas les coder. En fait, nous pouvons ajouter un JSON_PARTIAL_OUTPUT_ON_ERROR pour remplacer certaines valeurs non codables. Dans le code ci-dessous, nous pouvons l'utiliser pour remplacer NAN par 0.
$data = NAN; var_dump(json_encode($data)); // bool(false) var_dump(json_encode($data, JSON_PARTIAL_OUTPUT_ON_ERROR)); // 0
Pour les objets, le contenu après l'encodage JSON est le même que la sérialisation. Il n'aura que les propriétés de l'objet mais pas les méthodes. Après tout, la plus grande utilisation de JSON concerne la transmission de données, et les méthodes n'ont aucun effet pratique sur la transmission de données. Les propriétés différeront également selon leur encapsulation. Seules les propriétés publiques, c'est-à-dire les propriétés publiques, seront codées.
$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
作者:硬核项目经理
Apprentissage recommandé : "Tutoriel vidéo PHP"
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!