最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何使用Serializable接口來自定義PHP中類的序列化

 更新時間:2021年04月27日 11:59:45   作者:硬核項目經(jīng)理  
這篇文章主要介紹了如何使用Serializable接口來自定義PHP中類的序列化,幫助大家更好的理解和學習使用PHP,感興趣的朋友可以了解下

關(guān)于PHP中的對象序列化這件事兒,之前我們在很早前的文章中已經(jīng)提到過 __sleep() 和 __weakup() 這兩個魔術(shù)方法。今天我們介紹的則是另外一個可以控制序列化內(nèi)容的方式,那就是使用 Serializable 接口。它的使用和上述兩個魔術(shù)方法很類似,但又稍有不同。

Serializable接口

class A implements Serializable {
    private $data;
    public function __construct(){
        echo '__construct', PHP_EOL;
        $this->data = "This is Class A";
    }

    public function serialize(){
        echo 'serialize', PHP_EOL;
        return serialize($this->data);
    }

    public function unserialize($data){
        echo 'unserialize', PHP_EOL;
        $this->data = unserialize($data);
    }

    public function __destruct(){
        echo '__destruct', PHP_EOL;
    }

    public function __weakup(){
        echo '__weakup', PHP_EOL;
    }

    public function __sleep(){
        echo '__destruct', PHP_EOL;
    }
    
}

$a = new A();
$aSerialize = serialize($a);

var_dump($aSerialize);
// "C:1:"A":23:{s:15:"This is Class A";}"
$a1 = unserialize($aSerialize);
var_dump($a1);

這段代碼就是使用 Serializable 接口來進行序列化處理的,注意一點哦,實現(xiàn)了 Serializable 接口的類中的 __sleep() 和 __weakup() 魔術(shù)方法就無效了哦,序列化的時候不會進入它們。

Serializable 這個接口需要實現(xiàn)的是兩個方法,serialize() 方法和 unserialize() 方法,是不是和那兩個魔術(shù)方法完全一樣。當然,使用的方式也是一樣的。

在這里,我們多普及一點序列化的知識。對象序列化只能序列化它們的屬性,不能序列化他們方法。如果當前能夠找到對應的類模板,那么可以還原出這個類的方法來,如果沒有定義過這個類的模板,那么還原出來的類是沒有方法只有屬性的。我們通過這段代碼中的序列化字符串來分析:

  • "C:",指的是當前數(shù)據(jù)的類型,這個我面后面還會講,實現(xiàn) Serializable 接口的對象序列化的結(jié)果是 C: ,而沒有實現(xiàn)這個接口的對象序列化的結(jié)果是 O:
  • "A:",很明顯對應的是類名,也就是類的::class
  • "{xxx}",對象結(jié)構(gòu)和JSON一樣,也是用的花括號

各種類型的數(shù)據(jù)進行序列化的結(jié)果

下面我們再來看下不同類型序列化的結(jié)果。要知道,在PHP中,我們除了句柄類型的數(shù)據(jù)外,其他標量類型或者是數(shù)組、對象都是可以序列化的,它們在序列化字符串中是如何表示的呢?

$int = 110;
$string = '110';
$bool = FALSE;
$null = NULL;
$array = [1,2,3];

var_dump(serialize($int)); // "i:110;"
var_dump(serialize($string)); // "s:3:"110";"
var_dump(serialize($bool)); // "b:0;"
var_dump(serialize($null)); // "N;"
var_dump(serialize($array)); // "a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}"

上面的內(nèi)容還是比較好理解的吧。不過我們還是一一說明一下:

  • 數(shù)字類型:i:<值>
  • 字符串類型:s:<長度>:<值>
  • 布爾類型:b:<值:0或1>
  • NULL類型:N;
  • 數(shù)組:a:<長度>:<內(nèi)容>

對象在使用Serializable接口序列化時要注意的地方

接下來,我們重點講講對象類型,上面已經(jīng)提到過,實現(xiàn) Serializable 接口的對象序列化后的標識是有特殊情況的。上方序列化后的字符串開頭類型標識為 "C:",那么我們看看不實現(xiàn) Serializable 接口的對象序列化后是什么情況。

// 正常對象類型序列化的結(jié)果
class B {
    private $data = "This is Class B";

}
$b = new B();
$bSerialize = serialize($b);

var_dump ($bSerialize); // "O:1:"B":1:{s:7:"Bdata";s:15:"This is Class B";}"
var_dump($bSerialize);
var_dump(unserialize("O:1:\"B\":1:{s:7:\"\0B\0data\";s:15:\"This is Class B\";}"));

// object(B)#4 (1) {
//     ["data":"B":private]=>string(15) "This is Class B"
// }

果然,它開頭的類型標識是 "O:"。那么我們可以看出,"C:" 很大的概率指的是當前序列化的內(nèi)容是一個類類型,不是一個對象類型。它們之間其實并沒有顯著的差異,包括官方文檔上也沒有找到特別具體的說明。如果有過這方面的研究或者有相關(guān)資料的同學可以評論留言一起討論哈。

此外,如果我們手動將一個對象的 "O:" 轉(zhuǎn)成 "C:" 會怎么樣呢?

// 把O:替換成C:
var_dump(unserialize(str_replace('O:', 'C:', $bSerialize))); // false

抱歉,無法還原了。那么我們反過來,將上面 A 類也就是實現(xiàn)了 Serializable 接口的序列化字符串中的 "C:" 轉(zhuǎn)成 "O:" 呢?

// Warning: Erroneous data format for unserializing 'A'
var_dump(unserialize(str_replace('C:', 'O:', $aSerialize))); // false

嗯,會提示一個警告,然后同樣也無法還原了。這樣看來,我們的反序列化還是非常智能的,有一點點的不同都無法進行還原操作。

未定義類的反序列化操作

最后,我們來看看未定義類的情況下,直接反序列化一個對象。

// 模擬一個未定義的D類
var_dump(unserialize("O:1:\"D\":2:{s:7:\"\0D\0data\";s:15:\"This is Class D\";s:3:\"int\";i:220;}"));

// object(__PHP_Incomplete_Class)#4 (3) {
//     ["__PHP_Incomplete_Class_Name"]=>string(1) "D"
//     ["data":"D":private]=>string(15) "This is Class D"
//     ["int"]=>int(220)
// }

// 把未定義類的O:替換成C:
var_dump(unserialize(str_replace('O:', 'C:', "O:1:\"D\":2:{s:7:\"\0D\0data\";s:15:\"This is Class D\";s:3:\"int\";i:220;}"))); // false

從代碼中,我們可以看出,"C:" 類型的字符串依然無法反序列化成功。劃重點哦,如果是C:開頭的序列化字符串,一定需要是定義過的且實現(xiàn)了 Serializable 接口的類 才能反序列化成功。

另外,我們可以發(fā)現(xiàn),當序列化字符串中的模板不存在時,反序列化出來的類的類名是 __PHP_Incomplete_Class_Name 類,不像有類模板的反序列化成功直接就是正常的類名。

總結(jié)

其實從以上各種來看,個人感覺如果要保存數(shù)據(jù)或者傳遞數(shù)據(jù)的話,序列化并不是最好的選擇。畢竟包含了類型以及長度后將使得格式更為嚴格,而且反序列化回來的內(nèi)容如果沒有對應的類模板定義也并不是特別好用的,還不如直接使用 JSON 來得方便易讀。當然,具體情況具體分析,我們還是要結(jié)合場景來選擇合適的使用方式。

測試代碼:

github.com/zhangyue050…

以上就是如何使用Serializable接口來自定義PHP中類的序列化的詳細內(nèi)容,更多關(guān)于自定義PHP中類的序列化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • php中文字符截取防亂碼

    php中文字符截取防亂碼

    當漢字被截斷時,根據(jù)編碼規(guī)則他總是要把后邊的其他字符拉過來一起作為漢字解釋,這就是出現(xiàn)亂碼的原因。而值為0x81到0xff與0x00組合始終都顯示為“空” 根據(jù)這一特點,在substr的結(jié)果后面補上一個chr(0),就可以防止出現(xiàn)亂碼了
    2008-03-03
  • php實現(xiàn)利用phpexcel導出數(shù)據(jù)

    php實現(xiàn)利用phpexcel導出數(shù)據(jù)

    以下是對php中利用phpexcel導出數(shù)據(jù)的實現(xiàn)代碼進行了介紹,需要的朋友可以過來參考下
    2013-08-08
  • PHP實現(xiàn)貨幣換算的方法

    PHP實現(xiàn)貨幣換算的方法

    這篇文章主要介紹了PHP實現(xiàn)貨幣換算的方法,以實例形式較為詳細的講述了貨幣轉(zhuǎn)換的實現(xiàn)方法,并舉英鎊轉(zhuǎn)換美元為例講述具體用法,需要的朋友可以參考下
    2014-11-11
  • php通過array_shift()函數(shù)移除數(shù)組第一個元素的方法

    php通過array_shift()函數(shù)移除數(shù)組第一個元素的方法

    這篇文章主要介紹了php通過array_shift()函數(shù)移除數(shù)組第一個元素的方法,涉及php中array_shift()函數(shù)操作數(shù)組的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • php5.2 Json不能正確處理中文、GB編碼的解決方法

    php5.2 Json不能正確處理中文、GB編碼的解決方法

    json_encode對中文的處理是有問題,不能處理GB編碼,所有的GB編碼都會替換成空字符,下面有個不錯的解決方法,大家可以參考下
    2014-03-03
  • 淺析PHP數(shù)據(jù)導出知識點

    淺析PHP數(shù)據(jù)導出知識點

    本文是小編整理的關(guān)于PHP數(shù)據(jù)導出知識點的總結(jié)內(nèi)容,分析了經(jīng)常出現(xiàn)的問題,以及解決辦法,有興趣的朋友可以參考學習下。
    2018-02-02
  • PHP的加密方式及原理

    PHP的加密方式及原理

    有興趣研究了一下PHP的加密方式及原理,說白了算不上加密,只是用了URL編碼和BASE64編碼的轉(zhuǎn)換
    2012-06-06
  • PHP中錯誤與異常的日志記錄用法分析

    PHP中錯誤與異常的日志記錄用法分析

    這篇文章主要介紹了PHP中錯誤與異常的日志記錄用法,較為詳細的分析了php中錯誤與異常的區(qū)別以及日志記錄的相應使用技巧,需要的朋友可以參考下
    2016-08-08
  • PHP實現(xiàn)登陸表單提交CSRF及驗證碼

    PHP實現(xiàn)登陸表單提交CSRF及驗證碼

    本文主要介紹了PHP實現(xiàn)登陸表單提交CSRF及驗證碼的方法。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • php中使用getimagesize獲取圖片、flash等文件的尺寸信息實例

    php中使用getimagesize獲取圖片、flash等文件的尺寸信息實例

    這篇文章主要介紹了php中使用getimagesize獲取圖片、flash等文件的尺寸信息實例,需要的朋友可以參考下
    2014-04-04

最新評論

兴业县| 宿迁市| 庐江县| 巴青县| 丰都县| 连云港市| 孙吴县| 峨眉山市| 社旗县| 化德县| 忻城县| 河曲县| 蒙自县| 巨野县| 璧山县| 化德县| 蒙阴县| 博兴县| 神木县| 苏尼特左旗| 叶城县| 土默特左旗| 屯门区| 原阳县| 双桥区| 张北县| 泽州县| 无极县| 延庆县| 东乌珠穆沁旗| 陆河县| 泸定县| 北辰区| 夏河县| 屏边| 松原市| 重庆市| 定日县| 阿合奇县| 鸡东县| 清徐县|