其实这篇文章更应该针对python, 因为python默认情况下json序列化一个类对象时,是要报错的。

但是我觉得php的码农更多吧,而且主要是想传达一种思想,思想无国界哈。

那就拿PHP举粟,我们先来看看

1. json_encode对类的处理

先来看段测试代码:

class A {

public $a;

public $b;

private $c;

static public $d;

static protected $e;

public function __construct(){

$this->a = 1;

$this->b = 2;

$this->c = 3;

self::$d = 4;

self::$e = 5;

}

}

$obj = new A;

echo json_encode($obj);

输出结果为:

>> {"a":1,"b":2}

get_object_vars() 装饰下输出代码:

echo json_encode( get_object_vars($obj) );

输出结果还是:

>> {"a":1,"b":2}

综上我们差不多可以作个结论:

json_encode()序列化一个对象时,会先提取(get_object_vars)对象的公有(public)属性合并为一个数组,再进行序列化。private、protected、static属性以及类方法都将被丢弃。

1.1 不改变属性声明如何自定义JSON序列化的字段?

好,实操中真正碰到的问题来了。

class A {

public $a;

public $b;

public function __construct($a, $b){

$this->a = $a;

$this->b = $b;

}

public function sum(){

return $this->a + $this->b;

}

}

$obj = new A(1,2);

我想json_encode得到一个sum字段,如:

{"a":1, "b":2, "sum":3}

怎么实现呢?

童鞋们还得记PHP的类有个魔法方法 __toString(), 该方法是当尝试将对象转化为字符串时,就会调用该函数,从而得到期望的字符串。

class B{

public function __toString(){

return "我只是个大B";

}

}

echo(new B); // such as print(), strval(), ...

>> 我只是个大B

如果你是个Python coder, 这就不足为奇了,因为python的魔法方法真的不要花样太多。

好吧,那么有没有一个神奇的方法如 __json() 让我们来实现自定义JSON序列化呢?

暂时没有,不过PHP作者们早接到了这种需求,并做出了解决方案,请看:

1.2 接口JsonSerializable::jsonSerialize(),了解一下!

系统支持:(PHP 5 >= 5.4.0, PHP 7)

怎么用呢?看代码:

// 1. 类先要实现JsonSerializable接口

class A implements JsonSerializable {

public $a;

public $b;

public function __construct($a, $b){

$this->a = $a;

$this->b = $b;

}

public function sum(){

return $this->a + $this->b;

}

// 2. 实现jsonSerialize() 方法

public function jsonSerialize(){

// 定义我们需要的字段

return array(

"a"=>$this->a,

"b"=>$this->b,

"sum"=>$this->sum()

);

}

}

$obj = new A(1,2);

echo json_encode($obj);

这下满意了吧,看:

>> {"a":1,"b":2,"sum":3}

当类实现了jsonSerialize()时,json_encode(object)将使用jsonSerialize()取代get_object_vars()得到需要序列化的字段信息。

1.3 DateTime等系统对象如何处理

由于这些类是系统定义的,显示是无法添加上边说的接口,再定义一个子类做兼容也是个工作量不小的问题。

echo json_encode(date_create());

>> {"date":"2019-12-17 07:49:24.086271", "timezone_type":3, "timezone":"UTC"}

然而,因业务需求,所有接口里返回的时间对象,我只想要统一为:

YYYY-MM-DD HH:MM:SS 这种格式字符串

因此,建议大家在框架应用时

2. 自定义自己的json_encode方法

json_encode()显然是无法重写的了,那我就自己定义一个方法

2.1 my_json_encode()

然后整个项目查找json_encode替换为my_json_encode即可快速解决。

定义一个完全兼容json_encode()参数的方法

function my_json_encode($value, $options=0, $depth=512){

$value = my_json_handle($value);

return json_encode($value, $options, $depth);

}

代码里定义一个个性化的序列化处理方法:

2.2 my_json_handle($value)

在这里,你可以定义任何数据类型如何JSON序列化。

function my_json_handle($mixed, $depth=512, $recursion=1){

// recursion limited.

if($recursion >= $depth){

return print_r($mixed, true);

}

// 这是一个类对象数据

if(is_object($mixed)){

// 假设遇到DateTime数据, 输出为我们想要的

if($mixed instanceof DateTime || $mixed instanceof DateTimeImmutable){

return date_format($mixed, 'Y-m-d H:i:s');

}

// 你可以在这里自定义更多系统预设类的处理...

// 优先兼容实现了jsonSerialize()方法的类.

if($mixed instanceof JsonSerializable){

$mixed = $mixed->jsonSerialize();

}

elseif(method_exists($mixed, "__json")){

// 添加 __json() 魔法方法支持.

// 个人感觉 __json()比jsonSerialize()更科学且好记

// 类不需要再 implements JsonSerializable

$mixed = $mixed->__json();

}

// 默认get_object_vars()提取属性字段

if(is_object($mixed)){

$mixed = get_object_vars($mixed);

}

// 上边的if判断里没有像DateTime那样直接return $mixed

// 是因为可能得到是个可迭代的数据, 我们需要再进行迭代处理

}

// 可迭代的嵌套数据

if(is_array($mixed)){

foreach($mixed as $k=>$v){

// 当前迭代层级+1

$mixed[$k] = my_json_handle($v, $depth, $recursion+1);

}

}

return $mixed;

}

2.3 测试下我们的成果

// 不需要再 implements JsonSerializable

class A {

public $a;

public $b;

public $datetime;

public function __construct($a, $b){

$this->a = $a;

$this->b = $b;

$this->datetime = date_create("now", new DateTimeZone('+0800'));

}

public function sum(){

return $this->a + $this->b;

}

// 只需实现 __json() 方法

public function __json(){

// 定义我们需要的字段

return array(

"datetime"=>$this->datetime,

"timestamp"=>$this->datetime->getTimestamp(),

"sum"=>$this->sum()

);

}

}

echo my_json_encode(new A(1,2));

>> {"datetime":"2019-12-17 16:34:15", "timestamp":1576571655, "sum":3}

当你在项目中=使用ORM框架,并定义了大量的Model,在json序列化这些Model时,你会发现这篇文章还是有很实用的。

能规范你的接口输出字段,ajax接口不会经常多字段或少字段,同一个字段一会是字符串一会又是整型的各种尴尬。

后记

PHP中的标量(Scalar Data), 目前只发现float浮点数据在json_encode时可能出现溢出,PHP7可通过配置

serialize_precision = -1

解决。

另外浏览器端可能不支持长整型,有些订单ID位数比较长的时候(大于32bit整数),浏览器端JSON.parse()的时候就容易被截短数据,后台处理时可以把它转化为字符串。

php json对象取数据类型,PHP如何科学地json_encode类对象数据相关推荐

  1. 对Spring Data JPA中的page对象下的content属性里的实体类对象转换为dto对象

    对Spring Data JPA中的page对象下的content属性里的实体类对象转换为dto对象. 刚开始试遍历content,进行转换,添加到新的list中,再set进去page.后来发现pag ...

  2. python 对象创建_从Python中的基类对象创建对象

    我有一个基类:class Animal(object): def __init__(self, name=None, food=None): self.name = name self.food = ...

  3. C++对象模型1——类对象的sizeof、static成员、对象模型、this指针

    一.类对象的sizeof 1.空类对象的sizeof class test3{ };int main(int argc, char const *argv[]) { test3 t;cout<& ...

  4. C++类对象在内存中的布局

    目录 一.前言 二.C++ 类对象的内存布局 2.1 只有数据成员的对象 2.2 没有虚函数的对象 2.3 拥有仅一个虚函数的类对象 2.4 拥有多个虚函数的类对象 三.继承关系中的C++类对象内存分 ...

  5. JAVA 面向对象 类 对象 封装

    面向对象概念 在学习面向对象之前,我们可以先了解一下面向过程. 面向过程是一种编程思想,它强调的是过程,意思是我们做任何事,都需要亲力亲为. 面向对象也是一种编程思想,相对于面向过程,我们的身份可以由 ...

  6. ndarray 与 array 的区别 关系,所以ndarray是一个类对象,而array是一个方法

    ndarray 与 array 的区别 关系 置顶 wanglll* 2020-02-06 20:00:37  8455  已收藏 17 分类专栏: 数据分析 文章标签: numpy 版权 ndarr ...

  7. 【学习笔记】类对象的内存释放

    类对象的内存释放 整理转自-<SAP ABAP 面向对象程序设计(原则.模式及实践)> 类对象与其他数据变量一样,都是要占据程序内存的,如果确定后续程序不会再使用对象实例,我们就可以删除对 ...

  8. python创建变量_Python每天一分钟:给类对象动态新增/删除成员变量和方法(函数)...

    一般类对象新增变量或方法的过程 在面向对象(OOP)的编程方法中,如果需要给实例化的类对象新增方法或者属性,一般都是在class类的定义中新增内容,然后才能用类对象来调用新增的方法或变量.如在C++中 ...

  9. Java 中,类、类对象、泛型之间的转换

    Java 中,类.类对象.泛型之间的转换 R 为非泛型 获得类 通过类型名来获得类 通过对象来获得类 通过类名字符串来获得类 通过类来获得类名字符串 通过类来获得对象 使用 R 的无参数构造器来创建对 ...

最新文章

  1. Data - 数据思维 - 上篇
  2. 用MySQL创建数据库和数据库表
  3. 在Eclipse中使用Maven 2.x指南
  4. Linux中/proc目录下文件详解(二)
  5. 一种比sys.path更好的获得当前脚本路径的方法
  6. Scala 键盘录入对象StdIn/特质/伴生对象
  7. windows离线安装grunt_chrome火狐离线安装包下载
  8. 给原型扩展一下tirm方法
  9. 解决docker容器开启端口映射后,会自动在防火墙上打开端口的问题
  10. Idea tomcat控制台日志乱码
  11. 博途v16tia项目服务器,博途V16与scout TIA
  12. windows下运行nacos
  13. 用perl操作excel的介绍
  14. SurfaceView 实现 转盘抽奖
  15. PostSQL | Debug记录
  16. 超牛逼的性能调优利器 — 火焰图
  17. 编译x86_64老是不过,iphone模拟器debug不了解决方法
  18. ibmr系列服务器怎么装架子,【R440/R540/R640/R740 R820 R930 DELL服务器导轨 滑轨 支架 理线架】价格_厂家 - 中国供应商...
  19. android fresco 圆角,圆角和圆圈
  20. Cesium之3D拉伸显示行政区

热门文章

  1. tuple 方法总结整理
  2. C#中的快捷键,可以更方便的编写代码
  3. django 的form登录 注册
  4. 创建、添加字段IFields
  5. Android WebView使用
  6. 一些windows下调试网络的命令行
  7. C语言程序设计之回调函数实现方法
  8. 全球超算500强榜单更新:美国Summit居首,中国上榜227台
  9. 计算机视觉开源库OpenCV之CommandLineParser使用方法
  10. pelco-d协议数据解析示例