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对象序列化也是一个比较普遍的功能,能够把一个对象进行串行化以后变成一个字符串,能够保存或者传输。我们先看一个例子:
- classTestClass
- {
- var$a;
- var$b;
- functionTestClass()
- {
- $this->a="Thisisa";
- $this->b="Thisisb";
- }
- functiongetA()
- {
- return$this->a;
- }
- functiongetB()
- {
- return$this->b;
- }
- }
- $obj=newTestClass;
- $str=serialize($obj);
- echo$str;
输出结果:
- O:9:"TestClass":2:{s:1:"a";s:9:"Thisisa";s:1:"b";s:9:"Thisisb";}
我们来分析一个对象串行化之后的字符串。
- O:9:"TestClass":2:
- {
- s:1:"a";s:9:"Thisisa";
- 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都包含此文件。
- <?php
- //classa.inc:
- classA
- {
- var$one=;
- functionshow_one()
- {
- echo$this->one;
- }
- }
- //page1.php:
- include("classa.inc");
- $a=newA;
- $s=serialize($a);
- //将$s存放在某处使page2.php能够找到
- $fp=fopen("store","w");
- fputs($fp,$s);
- fclose($fp);
- //page2.php:
- //为了正常解序列化需要这一行
- include("classa.inc");
- $s=implode("",@file("store"));
- $a=unserialize($s);
- //现在可以用$a对象的show_one()函数了
- $a->show_one();
- ?>
添加数据的时候,几个一组几个一组的情况,总不见得每新加一组就新添加个字段,就用序列化存到字段类型为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进程死掉,日志
- 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环境上。
php序列化问题的更多相关文章
- 【.net 深呼吸】序列化中的“引用保留”
假设 K 类中有两个属性/字段的类型相同,并且它们引用的是同一个对象实例,在序列化的默认处理中,会为每个引用单独生成数据. 看看下面两个类. [DataContract] public class 帅 ...
- 【.net 深呼吸】设置序列化中的最大数据量
欢迎收看本期的<老周吹牛>节目,由于剧组严重缺钱,故本节目无视频无声音.好,先看下面一个类声明. [DataContract] public class DemoObject { [Dat ...
- 用dubbo时遇到的一个序列化的坑
首先,这是标题党,问题并不是出现在序列化上,这是报错的一部分: Caused by: com.alibaba.dubbo.remoting.RemotingException: Failed to s ...
- Unity 序列化
Script Serialization http://docs.unity3d.com/Manual/script-Serialization.html 自定义序列化及例子: http://docs ...
- Unity 序列化 总结
查找了 Script Serialization http://docs.unity3d.com/Manual/script-Serialization.html 自定义序列化及例子: http:// ...
- [C#] C# 知识回顾 - 序列化
C# 知识回顾 - 序列化 [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902005.html 目录 序列化的含义 通过序列化保存对象数据 众 ...
- Newtonsoft.Json设置类的属性不序列化
参考页面: http://www.yuanjiaocheng.net/webapi/parameter-binding.html http://www.yuanjiaocheng.net/webapi ...
- C# 序列化与反序列化几种格式的转换
这里介绍了几种方式之间的序列化与反序列化之间的转换 首先介绍的如何序列化,将object对象序列化常见的两种方式即string和xml对象; 第一种将object转换为string对象,这种比较简单没 ...
- Netty实现高性能RPC服务器优化篇之消息序列化
在本人写的前一篇文章中,谈及有关如何利用Netty开发实现,高性能RPC服务器的一些设计思路.设计原理,以及具体的实现方案(具体参见:谈谈如何使用Netty开发实现高性能的RPC服务器).在文章的最后 ...
- .Net深入实战系列—JSON序列化那点事儿
序 当前主流的序列化JSON字符串主要有两种方式:JavaScriptSerializer及Json.net(Nuget标识:Newtonsoft.Json).JavaScriptSerializer ...
随机推荐
- 20181031noip模拟赛T1
思路: 我们会发现不合法的位置只有两种情况 要么在前半边,要么在后半边 那么,我们将序列劈两次 使两次的长度分别为: (n为偶数时要特判一下,因为根本不可能) (n/2),(n/2+1) (n/2+1 ...
- LR--用栈实现移进--归约分析(demo)
1.考虑文法 \(E->E+E\) \(E->E*E\) \(E->id\) 2.最右推导 不难看出,这个文法是而二义的,所以有多个最右推导 3.移进归约 用一个栈存文法符号,用输入 ...
- 【TOJ 1072】编辑距离(动态规划)
描述 假设字符串的基本操作仅为:删除一个字符.插入一个字符和将一个字符修改成另一个字符这三种操作. 我们把进行了一次上述三种操作的任意一种操作称为进行了一步字符基本操作. 下面我们定义两个字符串的编辑 ...
- 关于python文件问题
一.python内部的首行命令 #!/usr/bin/env python #_*_coding:utf8_*_ 第一条命令用于Linux系统中的./命令,用于声明用什么Python解释器.第二条命令 ...
- 树莓派3B+SimpleCV上连接iPhone4s摄像头
目的:把iPhone4s当成网络摄像头,通过wifi连接到树莓派上,做为树莓派的摄像头. 1. iPhone4s上安装mini WebCam应用. 很旧的一个app, 没有密码,简单,无广告,免费. ...
- 跟着马哥学python-day02
1. 运算符 计算机可以进行的运算有很多种,可不只加减乘除这么简单,运算按种类可分为算数运算.比较运算.逻辑运算.赋值运算.成员运算.身份运算.位运算. 1.1 算数运算 以下假设变量:a=10,b= ...
- 短连接、长连接、轮询、长轮询、WebSocket
短连接 建立连接——数据传输——关闭连接...建立连接——数据传输——关闭连接 定义:短连接是指通讯双方有数据交互时,就建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送. 应 ...
- 浅析Vue.js 中的条件渲染指令
1 应用于单个元素 Vue.js 中的条件渲染指令可以根据表达式的值,来决定在 DOM 中是渲染还是销毁元素或组件. html: <div id="app"> < ...
- 5.18-笨办法学python-习题16(write)
from sys import argv script,filename=argv #固定模式啦 print("we're going to erase %r."%filename ...
- 20155215 2016-2017-2 《Java程序设计》第3周学习总结
20155215 2016-2017-2 <Java程序设计>第3周学习总结 教材学习内容总结 第四章 第四章主要讲了类的构建,数组对象,字符串对象的构建与操作等.要学会区分基本类型与类类 ...