zoukankan      html  css  js  c++  java
  • php序列化问题

    序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。

    1. serialize和unserialize函数

    这两个是序列化和反序列化PHP中数据的常用函数。

    <?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));

    但是base64编码将增加字符串的长度。为了克服这个问题,可以和gzcompress一起使用。

    //定义一个用来序列化对象的函数

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

    //反序列化
    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 plaincopy在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环境上。
  • 相关阅读:
    2-4安卓自学
    2-3安卓自学
    2-2安卓自学
    2-1安卓自学
    20210121 Sqlit数据库
    20210119 Sqlit数据库
    20210118 android学习
    20210117 android学习
    20210115 android学习
    20210114 android学习
  • 原文地址:https://www.cnblogs.com/clphp/p/4919595.html
Copyright © 2011-2022 走看看