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 ...
随机推荐
- Oracle 执行计划的查看方式
访问数据的方法:一.访问表的方法:1.全表扫描,2.ROWID扫描 二.访问索引的方法:1.索引唯一性扫描,2.索引范围扫描,3.索引全扫 ...
- 【js】javaScript 执行机制
javascript 是一门单线程语言(按照语句一行一行的执行) let a = '1'; console.log(a); let b = '2'; console.log(b); 这样子正常执行是没 ...
- Hadoop(二)CentOS7.5搭建Hadoop2.7.6完全分布式集群
一 完全分布式集群(单点) Hadoop官方地址:http://hadoop.apache.org/ 1 准备3台客户机 1.1防火墙,静态IP,主机名 关闭防火墙,设置静态IP,主机名此处略,参考 ...
- 如何通过审计安全事件日志检测密码喷洒(Password Spraying)攻击
许多渗透测试人员和攻击者通常都会使用一种被称为“密码喷洒(Password Spraying)”的技术来进行测试和攻击.对密码进行喷洒式的攻击,这个叫法很形象,因为它属于自动化密码猜测的一种.这种针对 ...
- vue中-webkit-box-orient:vertical打包放到线上不显示
解决方法: 1.找到build文件夹 下的webpack.prod.conf.js文件 2.注释new OptimizeCSSPlugin({ css ...
- SpringBoot 启动报The Java Virtual Machine has not been configured to use the desired default character encoding (UTF-8)
解决方法: 启动的时候在VM中添加 Dfile.encoding=UTF-8 就好了!
- BrightScript 3D test - Roku (4)
My initial attempt to port over an old Actionscript program, here it goes in main.brs. Library " ...
- HIVE-分桶表的详解和创建实例
我们学习一下分桶表,其实分区和分桶这两个概念对于初学者来说是比较难理解的.但对于理解了的人来说,发现又是如此简单. 我们先建立一个分桶表,并尝试直接上传一个数据 buckets row format ...
- 20155230 《Java程序设计》实验五 Java网络编程及安全
20155230 <Java程序设计>实验五 Java网络编程及安全 实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验1 两人一组结对编程 ...
- java开发工具使用
一.MyEclipse软件的使用 1)ctrl+n新建文件 2)ctrl+d删除一行 3)alt+/提示补齐 (main/syso/syse/for遍历最近的数组) 4)ctrl+shift+f格式化 ...