php序列化問題

序列化是將變量轉換爲可保存或傳輸的字符串的過程;反序列化就是在適當的時候把這個字符串再轉化成原來的變量使用。這兩個過程結合起來,能夠輕鬆地存儲和傳輸數據,使程序更具維護性。php

1. serialize和unserialize函數

這兩個是序列化和反序列化PHP中數據的經常使用函數。html

<?php

$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');
 
//序列化數組
$s = serialize($a);
echo $s;
//輸出結果:a:3:{s:1:"a";s:5:"Apple";s:1:"b";s:6:"banana";s:1:"c";s:7:"Coconut";}

echo '<br /><br />';

//反序列化
$o = unserialize($s);

print_r($o);
//輸出結果 Array ( [a] => Apple [b] => banana [c] => Coconut )
 
?>

  

當數組值包含如雙引號、單引號或冒號等字符時,它們被反序列化後,可能會出現問題。爲了克服這個問題,一個巧妙的技巧是使用base64_encode和base64_decode。數據庫

$obj = array();
//序列化
$s = base64_encode(serialize($obj));
//反序列化
$original = unserialize(base64_decode($s)); json

可是base64編碼將增長字符串的長度。爲了克服這個問題,能夠和gzcompress一塊兒使用。數組

//定義一個用來序列化對象的函數服務器

function my_serialize( $obj )
{
return base64_encode(gzcompress(serialize($obj)));
} cookie

//反序列化
function my_unserialize($txt)
{
return unserialize(gzuncompress(base64_decode($txt)));
}函數

2. json_encode 和 json_decode

使用JSON格式序列化和反序列化是一個不錯的選擇: 性能

  • 使用json_encode和json_decode格式輸出要serialize和unserialize格式快得多。
  • JSON格式是可讀的。
  • JSON格式比serialize返回數據結果小。
  • JSON格式是開放的、可移植的。其餘語言也可使用它。

$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');

//序列化數組
$s = json_encode($a);
echo $s;
//輸出結果:{"a":"Apple","b":"banana","c":"Coconut"}測試

echo '<br /><br />';

//反序列化
$o = json_decode($s);

在上面的例子中,json_encode輸出長度比上個例子中serialize輸出長度顯然要短。

3. var_export 和 eval

var_export 函數把變量做爲一個字符串輸出;eval把字符串當成PHP代碼來執行,反序列化獲得最初變量的內容。

$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');

//序列化數組
$s = var_export($a , true);
echo $s;
//輸出結果: array ( 'a' => 'Apple', 'b' => 'banana', 'c' => 'Coconut', )

echo '<br /><br />';

//反序列化
eval('$my_var=' . $s . ';');

print_r($my_var);

4. wddx_serialize_value 和 wddx deserialize

wddx_serialize_value函數能夠序列化數組變量,並以XML字符串形式輸出。

$a = array('a' => 'Apple' ,'b' => 'banana' , 'c' => 'Coconut');

//序列化數組
$s = wddx_serialize_value($a);
echo $s;

//輸出結果(查看輸出字符串的源碼):<wddxPacket version='1.0'><header/><data><struct><var name='a'><string>Apple</string></var><var name='b'><string>banana</string></var><var name='c'><string>Coconut</string></var></struct></data></wddxPacket>

echo '<br /><br />';

//反序列化
$o = wddx_deserialize($s);

print_r($o);
//輸出結果:Array ( [a] => Apple [b] => banana 1 => Coconut )

 

能夠看出,XML標籤字符較多,致使這種格式的序列化仍是佔了不少空間。

小結

上述全部的函數在序列化數組變量時都能正常執行,但運用到對象就不一樣了。例如json_encode序列化對象就會失敗。反序列化對象時,unserialize和eval將有不一樣的效果。

 

 

 

 

 

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

PHP仍是比較經常使用的,因而我研究了一下PHP對象序列化,在這裏拿出來和你們分享一下,但願對你們有用。PHP對象序列化也是一個比較廣泛的功能,可以把一個對象進行串行化之後變成一個字符串,可以保存或者傳輸。咱們先看一個例子:

  1. classTestClass  
  2. {  
  3. var$a;  
  4. var$b;  
  5.  
  6. functionTestClass()  
  7. {  
  8. $this->a="Thisisa";  
  9. $this->b="Thisisb";  
  10. }  
  11.  
  12. functiongetA()  
  13. {  
  14. return$this->a;  
  15. }  
  16.  
  17. functiongetB()  
  18. {  
  19. return$this->b;  
  20. }  
  21. }  
  22. $obj=newTestClass;  
  23. $str=serialize($obj);  
  24. echo$str;  

輸出結果:

  1. O:9:"TestClass":2:{s:1:"a";s:9:"Thisisa";s:1:"b";s:9:"Thisisb";} 

咱們來分析一個對象串行化以後的字符串。

  1. O:9:"TestClass":2:  
  2. {  
  3. s:1:"a";s:9:"Thisisa";  
  4. s:1:"b";s:9:"Thisisb";  

首先看對於對象自己的內容:O:9:"TestClass":2:O是說明這是一個對象類型(object),而後9是表明對象的名字查過濃度,2是表明該對象有幾個屬性。在看兩個屬性的內容:s:1:"a";s:9:"Thisisa";其實跟數組的內容比較相似,第一項:s:1:"a";是描述屬性名稱的,第二項s:9:"Thisisa";是描述屬性值的。後面的屬性相似。先說一種PHP對象序列化的應用,下面的內容是PHP手冊上,沒有更改原文。serialize()返回一個字符串,包含着能夠儲存於PHP的任何值的字節流表示。unserialize()能夠用此字符串來重建原始的變量值。用序列化來保存對象能夠保存對象中的全部變量。對象中的函數不會被保存,只有類的名稱。

要可以unserialize()一個對象,須要定義該對象的類。也就是,若是序列化了page1.php中類A的對象$a,將獲得一個指向類A的字符串幷包含有全部$a中變量的值。若是要在page2.php中將其解序列化,重建類A的對象$a,則page2.php中必需要出現類A的定義。這能夠例如這樣實現,將類A的定義放在一個包含文件中,並在page1.php和page2.php都包含此文件。

  1. <?php 
  2. //classa.inc:  
  3. classA  
  4. {  
  5. var$one=1;  
  6.  
  7. functionshow_one()  
  8. {  
  9. echo$this->one;  
  10. }  
  11. }  
  12.  
  13. //page1.php:  
  14. include("classa.inc");  
  15.  
  16. $a=newA;  
  17. $s=serialize($a);  
  18. //將$s存放在某處使page2.php可以找到  
  19. $fp=fopen("store","w");  
  20. fputs($fp,$s);  
  21. fclose($fp);  
  22.  
  23. //page2.php:  
  24. //爲了正常解序列化須要這一行  
  25. include("classa.inc");  
  26.  
  27. $s=implode("",@file("store"));  
  28. $a=unserialize($s);  
  29.  
  30. //如今能夠用$a對象的show_one()函數了  
  31. $a->show_one();  
  32. ?> 

 

 

 

 

添加數據的時候,幾個一組幾個一組的狀況,總不見得每新加一組就新添加個字段,就用序列化存到字段類型爲text(我都設置爲text,由於通常不知道會出現多少個「組」)的字段中,取出時候反序列化成爲數組循環輸出就行

 

 

序列化某項的時候,會很省事,好比:form的提交,某個數據集中,由於序列化後就沒必要再在乎裏面的字符,是否是會注入等等。好處仍是不少的。

至少劣勢嘛,序列化後的字符數量要比序列化前的多,若是想放入cookie的時候須要注意長度,某些字符還須要轉義,放入到庫中的時候,由於長度不肯定,必須得用text的字段。



序列化是將變量轉換爲可保存或傳輸的字符串的過程;反序列化就是在適當的時候把這個字符串再轉化成原來的變量使用。這兩個過程結合起來,能夠輕鬆地存儲和傳輸數據,使程序更具維護性。 

PHP中的序列化和反序列化分別經過函數serialize()和unserialize()便可實現。serialize()的參數能夠是resource類型外的全部變量類型,最多見的是用來序列化對象,unseialize()將serialize的返回結果做爲參數,進行反序列化,獲得原對象。

在PHP中,序列化和反序列化不少地方均可以用到!~

例如:數據庫鏈接,序列化數組等等。



數據方面:
      1:升級到PHP5.5後,json,serialize,igbinary三種方式序列化後,大小沒有變化,說明這三種格式的對象結構沒有沒有變化,因此能夠無縫升級,msgpack因爲沒有以前的數據作對比,暫時未知。
      2:佔用空間方面,igbinary節省空間明顯優點,好比在json一個數組5.4k大小的數據,serialize方式要8.6k,而使用igbinary方式,僅需2.4k,近乎爲serialize方式的1/4,但在小數組方面msgpack方式更具優點,igbinary佔用空間123,而msgpack方式僅爲102。可是在大數組狀況下,明顯igbinary方式優點更明顯。大數組igbinary勝出,小數組msgpack勝出。
性能方面:
      1:在小數據時,json和原生serialize的性能都比PHP5.3版本有所提高,而在處理大數據量時,性能又有所降低。
      2:在序列化方面,msgpack方式性能最好,其次是json_encode的,再次是igbinary,這二者相差無幾,最差的爲原生serialize,原生serialize性能消耗大概爲json和igbinary方式的的1.4倍左右,而是msgpack方式的2倍。在大數組方面,序列化方便,基本上和小數組一致,只是igbinary性能教較json_encode方式有所提高。本輪msgpack勝出。
      3:在反序列方面igbinary的比序列化過程更快,固然也是最快的,可是這種快也是有成本代價的,參見最後的注意事項,最慢的爲json_decode方式,猜想緣由可能在於PHP做爲服務器端應用,最多的場景是encode,而decode的最多見的爲js處理方式,性能不是很理想。而msgpack反序列化性能基本上是它序列化的2倍。本輪igbinary勝出。
      4:總體性能對比,總體性能是序列化和反序列化之和,簡單對比會發現,json是最差的,次之是原生serialize,再次爲igbinary的方式,最優的爲msgpack,不過igbinary和msgpack相差真的很是小,而在佔用空間方面,小數據時msgpack勝出,大數據時igbinary勝出,算是各有千秋。因此,若是追求極致的性能,能夠考慮使用msgpack,若是對是使用空間要求苛刻,那就選擇igbinary方式,估計這也是PHPRedis選擇igbinary做爲內置序列化方式的緣由之一,另外還有一個緣由,考慮到Redis應用場景可能是一寫多讀,要保證反序列化性能足夠高,非igbinary莫屬。

使用igbinary並不是沒有代價,在測試中咱們發現,調用igbinary_unserialize時,傳遞非法數據,會致使整個php進程死掉,日誌

[html]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
 
  1. child 19131 exited on signal 11 (SIGSEGV) after  1.844938 seconds from start 1.844938 seconds from start  
估計是由於igbinary爲了提高性能,在unserialize時,沒有作相關格式驗證,致使整個進程異常退出。在使用Redis時,咱們先期使用SERIALIZE_PHP方式序列化,爲了提高性能,減小對Redis空間的浪費採用igbinary_serialize方式,再切換的時候不當心踩到這個坑,致使服務器響應出錯,直接502,幸好在daily環境上。
相關文章
相關標籤/搜索