關(guān)于PHP中的對(duì)象序列化這件事兒,之前我們?cè)诤茉缜暗奈恼轮幸呀?jīng)提到過(guò) __sleep() 和 __weakup() 這兩個(gè)魔術(shù)方法。今天我們介紹的則是另外一個(gè)可以控制序列化內(nèi)容的方式,那就是使用 Serializable 接口。它的使用和上述兩個(gè)魔術(shù)方法很類似,但又稍有不同。
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 接口來(lái)進(jìn)行序列化處理的,注意一點(diǎn)哦,實(shí)現(xiàn)了 Serializable 接口的類中的 __sleep() 和 __weakup() 魔術(shù)方法就無(wú)效了哦,序列化的時(shí)候不會(huì)進(jìn)入它們。
Serializable 這個(gè)接口需要實(shí)現(xiàn)的是兩個(gè)方法,serialize() 方法和 unserialize() 方法,是不是和那兩個(gè)魔術(shù)方法完全一樣。當(dāng)然,使用的方式也是一樣的。
在這里,我們多普及一點(diǎn)序列化的知識(shí)。對(duì)象序列化只能序列化它們的屬性,不能序列化他們方法。如果當(dāng)前能夠找到對(duì)應(yīng)的類模板,那么可以還原出這個(gè)類的方法來(lái),如果沒(méi)有定義過(guò)這個(gè)類的模板,那么還原出來(lái)的類是沒(méi)有方法只有屬性的。我們通過(guò)這段代碼中的序列化字符串來(lái)分析:
下面我們?cè)賮?lái)看下不同類型序列化的結(jié)果。要知道,在PHP中,我們除了句柄類型的數(shù)據(jù)外,其他標(biāo)量類型或者是數(shù)組、對(duì)象都是可以序列化的,它們?cè)谛蛄谢址惺侨绾伪硎镜哪兀?/p>
$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)容還是比較好理解的吧。不過(guò)我們還是一一說(shuō)明一下:
接下來(lái),我們重點(diǎn)講講對(duì)象類型,上面已經(jīng)提到過(guò),實(shí)現(xiàn) Serializable 接口的對(duì)象序列化后的標(biāo)識(shí)是有特殊情況的。上方序列化后的字符串開(kāi)頭類型標(biāo)識(shí)為 "C:",那么我們看看不實(shí)現(xiàn) Serializable 接口的對(duì)象序列化后是什么情況。
// 正常對(duì)象類型序列化的結(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" // }
果然,它開(kāi)頭的類型標(biāo)識(shí)是 "O:"。那么我們可以看出,"C:" 很大的概率指的是當(dāng)前序列化的內(nèi)容是一個(gè)類類型,不是一個(gè)對(duì)象類型。它們之間其實(shí)并沒(méi)有顯著的差異,包括官方文檔上也沒(méi)有找到特別具體的說(shuō)明。如果有過(guò)這方面的研究或者有相關(guān)資料的同學(xué)可以評(píng)論留言一起討論哈。
此外,如果我們手動(dòng)將一個(gè)對(duì)象的 "O:" 轉(zhuǎn)成 "C:" 會(huì)怎么樣呢?
// 把O:替換成C: var_dump(unserialize(str_replace('O:', 'C:', $bSerialize))); // false
抱歉,無(wú)法還原了。那么我們反過(guò)來(lái),將上面 A 類也就是實(shí)現(xiàn)了 Serializable 接口的序列化字符串中的 "C:" 轉(zhuǎn)成 "O:" 呢?
// Warning: Erroneous data format for unserializing 'A' var_dump(unserialize(str_replace('C:', 'O:', $aSerialize))); // false
嗯,會(huì)提示一個(gè)警告,然后同樣也無(wú)法還原了。這樣看來(lái),我們的反序列化還是非常智能的,有一點(diǎn)點(diǎn)的不同都無(wú)法進(jìn)行還原操作。
最后,我們來(lái)看看未定義類的情況下,直接反序列化一個(gè)對(duì)象。
// 模擬一個(gè)未定義的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:" 類型的字符串依然無(wú)法反序列化成功。劃重點(diǎn)哦,如果是C:開(kāi)頭的序列化字符串,一定需要是定義過(guò)的且實(shí)現(xiàn)了 Serializable 接口的類 才能反序列化成功。
另外,我們可以發(fā)現(xiàn),當(dāng)序列化字符串中的模板不存在時(shí),反序列化出來(lái)的類的類名是 __PHP_Incomplete_Class_Name 類,不像有類模板的反序列化成功直接就是正常的類名。
其實(shí)從以上各種來(lái)看,個(gè)人感覺(jué)如果要保存數(shù)據(jù)或者傳遞數(shù)據(jù)的話,序列化并不是最好的選擇。畢竟包含了類型以及長(zhǎng)度后將使得格式更為嚴(yán)格,而且反序列化回來(lái)的內(nèi)容如果沒(méi)有對(duì)應(yīng)的類模板定義也并不是特別好用的,還不如直接使用 JSON 來(lái)得方便易讀。當(dāng)然,具體情況具體分析,我們還是要結(jié)合場(chǎng)景來(lái)選擇合適的使用方式。
測(cè)試代碼:
github.com/zhangyue050…
以上就是如何使用Serializable接口來(lái)自定義PHP中類的序列化的詳細(xì)內(nèi)容,更多關(guān)于自定義PHP中類的序列化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
標(biāo)簽:克拉瑪依 唐山 鶴崗 白城 鷹潭 柳州 六安 遼陽(yáng)
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《如何使用Serializable接口來(lái)自定義PHP中類的序列化》,本文關(guān)鍵詞 如何,使用,Serializable,接口,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。