php json对象取数据类型,PHP如何科学地json_encode类对象数据
其實(shí)這篇文章更應(yīng)該針對python, 因?yàn)閜ython默認(rèn)情況下json序列化一個類對象時,是要報(bào)錯的。
但是我覺得php的碼農(nóng)更多吧,而且主要是想傳達(dá)一種思想,思想無國界哈。
那就拿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);
輸出結(jié)果為:
>> {"a":1,"b":2}
get_object_vars() 裝飾下輸出代碼:
echo json_encode( get_object_vars($obj) );
輸出結(jié)果還是:
>> {"a":1,"b":2}
綜上我們差不多可以作個結(jié)論:
json_encode()序列化一個對象時,會先提取(get_object_vars)對象的公有(public)屬性合并為一個數(shù)組,再進(jìn)行序列化。private、protected、static屬性以及類方法都將被丟棄。
1.1 不改變屬性聲明如何自定義JSON序列化的字段?
好,實(shí)操中真正碰到的問題來了。
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}
怎么實(shí)現(xiàn)呢?
童鞋們還得記PHP的類有個魔法方法 __toString(), 該方法是當(dāng)嘗試將對象轉(zhuǎn)化為字符串時,就會調(diào)用該函數(shù),從而得到期望的字符串。
class B{
public function __toString(){
return "我只是個大B";
}
}
echo(new B); // such as print(), strval(), ...
>> 我只是個大B
如果你是個Python coder, 這就不足為奇了,因?yàn)閜ython的魔法方法真的不要花樣太多。
好吧,那么有沒有一個神奇的方法如 __json() 讓我們來實(shí)現(xiàn)自定義JSON序列化呢?
暫時沒有,不過PHP作者們早接到了這種需求,并做出了解決方案,請看:
1.2 接口JsonSerializable::jsonSerialize(),了解一下!
系統(tǒng)支持:(PHP 5 >= 5.4.0, PHP 7)
怎么用呢?看代碼:
// 1. 類先要實(shí)現(xiàn)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. 實(shí)現(xiàn)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}
當(dāng)類實(shí)現(xiàn)了jsonSerialize()時,json_encode(object)將使用jsonSerialize()取代get_object_vars()得到需要序列化的字段信息。
1.3 DateTime等系統(tǒng)對象如何處理
由于這些類是系統(tǒng)定義的,顯示是無法添加上邊說的接口,再定義一個子類做兼容也是個工作量不小的問題。
echo json_encode(date_create());
>> {"date":"2019-12-17 07:49:24.086271", "timezone_type":3, "timezone":"UTC"}
然而,因業(yè)務(wù)需求,所有接口里返回的時間對象,我只想要統(tǒng)一為:
YYYY-MM-DD HH:MM:SS 這種格式字符串
因此,建議大家在框架應(yīng)用時
2. 自定義自己的json_encode方法
json_encode()顯然是無法重寫的了,那我就自己定義一個方法
2.1 my_json_encode()
然后整個項(xiàng)目查找json_encode替換為my_json_encode即可快速解決。
定義一個完全兼容json_encode()參數(shù)的方法
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)
在這里,你可以定義任何數(shù)據(jù)類型如何JSON序列化。
function my_json_handle($mixed, $depth=512, $recursion=1){
// recursion limited.
if($recursion >= $depth){
return print_r($mixed, true);
}
// 這是一個類對象數(shù)據(jù)
if(is_object($mixed)){
// 假設(shè)遇到DateTime數(shù)據(jù), 輸出為我們想要的
if($mixed instanceof DateTime || $mixed instanceof DateTimeImmutable){
return date_format($mixed, 'Y-m-d H:i:s');
}
// 你可以在這里自定義更多系統(tǒng)預(yù)設(shè)類的處理...
// 優(yōu)先兼容實(shí)現(xiàn)了jsonSerialize()方法的類.
if($mixed instanceof JsonSerializable){
$mixed = $mixed->jsonSerialize();
}
elseif(method_exists($mixed, "__json")){
// 添加 __json() 魔法方法支持.
// 個人感覺 __json()比jsonSerialize()更科學(xué)且好記
// 類不需要再 implements JsonSerializable
$mixed = $mixed->__json();
}
// 默認(rèn)get_object_vars()提取屬性字段
if(is_object($mixed)){
$mixed = get_object_vars($mixed);
}
// 上邊的if判斷里沒有像DateTime那樣直接return $mixed
// 是因?yàn)榭赡艿玫绞莻€可迭代的數(shù)據(jù), 我們需要再進(jìn)行迭代處理
}
// 可迭代的嵌套數(shù)據(jù)
if(is_array($mixed)){
foreach($mixed as $k=>$v){
// 當(dāng)前迭代層級+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;
}
// 只需實(shí)現(xiàn) __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}
當(dāng)你在項(xiàng)目中=使用ORM框架,并定義了大量的Model,在json序列化這些Model時,你會發(fā)現(xiàn)這篇文章還是有很實(shí)用的。
能規(guī)范你的接口輸出字段,ajax接口不會經(jīng)常多字段或少字段,同一個字段一會是字符串一會又是整型的各種尷尬。
后記
PHP中的標(biāo)量(Scalar Data), 目前只發(fā)現(xiàn)float浮點(diǎn)數(shù)據(jù)在json_encode時可能出現(xiàn)溢出,PHP7可通過配置
serialize_precision = -1
解決。
另外瀏覽器端可能不支持長整型,有些訂單ID位數(shù)比較長的時候(大于32bit整數(shù)),瀏覽器端JSON.parse()的時候就容易被截短數(shù)據(jù),后臺處理時可以把它轉(zhuǎn)化為字符串。
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的php json对象取数据类型,PHP如何科学地json_encode类对象数据的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php中mb substr,php中中文
- 下一篇: java的语法树,JAVA语言语法树.d