其实这篇文章应该更针对python,因为默认情况下python在json序列化类对象时会报错。但是我觉得php码农比较多,主要是为了传达一个思想,没有国界。那么以PHP为例,我们来看一下1.json_encode对类的处理先看一段测试代码:classA{public$a;公共$b;私人$c;静态公共$d;静态保护$e;公共函数__construct(){$this->a=1;$this->b=2;$this->c=3;自我::$d=4;自我::$e=5;}}$obj=newA;echojson_encode($obj);输出结果为:>>{"a":1,"b":2}get_object_vars()装饰输出代码:echojson_encode(get_object_vars($obj));output结果依然是:>>{"a":1,"b":2}综上所述,我们几乎可以得出一个结论:json_encode()序列化一个对象时,会先提取(get_object_vars)公共(public))对象的属性,合并成一个数组,然后序列化。private、protected、static属性和类方法将被丢弃。1.1如何在不改变属性声明的情况下自定义JSON序列化字段?好了,实践中真正遇到的问题来了。A类{公共$a;公共$b;公共函数__construct($a,$b){$this->a=$a;$this->b=$b;}publicfunctionsum(){return$this->a+$this->b;}}$obj=newA(1,2);我想json_encode得到一个总和字段,如:{"a":1,"b":2,"sum":3}如何实现?童鞋们还得记住,PHP类有一个神奇的方法__toString(),当试图将一个对象转换成字符串来获取想要的字符串时会调用它。classB{publicfunction__toString(){return"我只是个大B";}}回声(新乙);//比如print(),strval(),...>>如果你是Pythoncoder,我就是个大B,这并不奇怪,因为python的魔术方法真的没有太多花样。好的,那么有没有像__json()这样的神奇方法可以让我们实现自定义JSON序列化呢?还没有,但是PHP作者已经接到这个需求并做了解决方案,请看:1.2接口JsonSerializable::jsonSerialize(),一探究竟!系统支持:(PHP5>=5.4.0,PHP7)如何使用?看代码://1.类首先要实现JsonSerializable接口classAimplementsJsonSerializable{public$a;公共$b;公共函数__construct($a,$b){$this->a=$a;$this->b=$b;}publicfunctionsum(){返回$this->a+$this->b;}//2.实现jsonSerialize()方法publicfunctionjsonSerialize(){//定义我们需要的字段returnarray("a"=>$this->a,"b"=>$this->b,"求和"=>$this->求和());}}$obj=newA(1,2);echojson_encode($obj);现在你满意了吗,看:>>{"a":1,"b":2,"sum":3}当类实现jsonSerialize()时,json_encode(object)会使用jsonSerialize()而不是get_object_vars()获取需要序列化的字段信息。1.3如何处理DateTime等系统对象由于这些类都是系统定义的,不可能添加上面提到的接口,为了兼容定义一个子类也是一个需要大量工作的问题。echojson_encode(date_create());>>{"date":"2019-12-1707:49:24.086271","timezone_type":3,"timezone":"UTC"}但是由于业务需要,所有interfaces我只是想将这种格式返回的时间对象统一成:YYYY-MM-DDHH:MM:SS。所以建议大家2.自定义自己的json_encode方法json_encode()显然不能被重写,那我自己定义一个方法2.1my_json_encode(),然后整个项目找json_encode替换成my_json_encode即可快点解决。定义一个完全兼容json_encode()参数的方法functionmy_json_encode($value,$options=0,$depth=512){$value=my_json_handle($value);returnjson_encode($value,$options,$depth);}在代码中定义一个个性化的序列化处理方法:2.2my_json_handle($value)在这里,你可以定义如何序列化JSON中的任何数据类型。functionmy_json_handle($mixed,$depth=512,$recursion=1){//递归受限。如果($recursion>=$depth){returnprint_r($mixed,true);}//这是一个类对象数据if(is_object($mixed)){//假设遇到DateTime数据,输出就是我们想要的if($mixedinstanceofDateTime||$mixedinstanceofDateTimeImmutable){returndate_format($混合,'Y-m-dH:i:s');}//这里可以自定义更多系统默认类的处理...//优先兼容实现了jsonSerialize()方法的类。if($mixedinstanceofJsonSerializable){$mixed=$mixed->jsonSerialize();}elseif(method_exists($mixed,"__json")){//添加__json()魔术方法支持。//个人觉得__json()比jsonSerialize()更科学也好记//Class不需要实现JsonSerializable$mixed=$mixed->__json();}//默认get_object_vars()提取属性字段if(is_object($mixed)){$mixed=get_object_vars($mixed);}//上面的if判断中,没有像DateTime那样直接返回$mixed//因为有可能得到可迭代的数据,所以我们需要再次迭代}//可迭代的嵌套数据if(is_array($mixed)){foreach($mixedas$k=>$v){//当前迭代层级+1$mixed[$k]=my_json_handle($v,$depth,$recursion+1);}}return$mixed;}2.3测试我们的结果//不需要实现JsonSerializableclassA{public$a;公共$b;公共$日期时间;公共函数__construct($a,$b){$this->a=$a;$this->b=$b;$this->datetime=date_create("now",newDateTimeZone('+0800'));}publicfunctionsum(){返回$this->a+$this->b;}//实现__json()方法即可publicfunction__json(){//定义我们需要的字段returnarray("datetime"=>$this->datetime,"timestamp"=>$this->datetime->getTimestamp(),"求和"=>$this->求和());}}echomy_json_encode(newA(1,2));>>{"datetime":"2019-12-1716:34:15","timestamp":1576571655,"sum":3当你在项目中使用ORM框架,定义了大量的Models,当你将这些Models序列化到json中时,你会发现这篇文章规范你的接口输出字段还是很实用的,ajax接口不会经常许多字段或几个字段,同一个字段有时是一个字符串有时是一个整数。PHP中的后记标量数据。目前只发现float浮点数据在json_encode时可能会溢出。PHP7可以通过配置serialize_precision=-1来解决。另外,浏览器端可能不支持长整数。当一些订单ID比较长(大于32bit整数)时,在浏览器端JSON.parse()执行时,数据很容易被截断,可以在后台处理时进行转换。作为一个字符串。
