PHP中的串行化变量和序列化对象


Posted in PHP onSeptember 05, 2006

串行化大概就是把一些变量转化成为字符串的字节流的形式,这样比较容易传输、存储。当然,关是传输存储没有什么,关键是变成串的形式以后还能够转化回来,而且能够保持原来数据的结构。

在PHP中有多串行化处理的函数:serialize(),该函数把任何变量值(除了资源变量)转化为字符串的形式,可以把字符串保存到文件里,或者注册为Session,乃至于使用curl来模拟GET/POST来传输变量,达到RPC的效果。

如果要将串行化的变量转化成PHP原始的变量值,那么可以使用unserialize()函数。

一、变量串行化

我们举简单的例子来说明串行化,以及它的存储格式。

整型:

$var = 23;

echo serialize($var);

输出:

i:23;

浮点型:

$var = 1.23;

echo serialize($var);

输出:

d:1.229999999999999982236431605997495353221893310546875;

字符串:

$var = "This is a string";

echo serialize($var);

$var = "我是变量";

echo serialize($var);

输出:

s:16:"This is a string";

s:8:"我是变量";

布尔型:

$var = true;

echo serialize($var);

$var = false;

echo serialize($var);

输出:

b:1;

b:0;

上面这些基本类型串行化之后的情况很清楚,串行化之后的存储格式是:

变量类型:[变量长度:]变量值;

就是第一位字符代表变量类型,第二个:代表分割,变量长度是可选的,就是在字符串类型里有,其他类型没有,最后一个就是变量值,每个串行化的值以";"作为结束。

比如我们整型数字23串行化之后就是:i:23,那么它没有长度,只有类型和变量值,i代表integer,通过冒号分割,后面保存的是整型值23,包括浮点型(双字节型)也是一样。布尔型的话,类型是b(boolean),如果是true的话,那么串行化的值是1,如果是false那么值就是0。字

符串值话中间会多一个保存的值得,保存字符串的长度值,比如字符串"This is a string",那么生成的串行化的值是 s:16:"This is a string"; s是string,代表类型,中间的16就是该字符串的长度,如果是中文的话,那么每个中文是两个字符来保存的,比如字符串 "我是变量",生成的串行化值是:s:8:"我是变量"; 就是8个字符的长度。

下面我们重点来讲一下数组变量串行化。

数组变量:

$var = array("abc", "def", "xyz", "123");
echo serialize($var);

输出:

a:4:{i:0;s:3:"abc";i:1;s:3:"def";i:2;s:3:"xyz";i:3;s:3:"123";}

就是把我的数组 $var 串行化得到的字符串值,我们的$var数组包括4个字符串元素,分别是"abc", "def", "xyz", "123",我们来分析一下串行化后的数据,为了简便起见,我们把串行化的数据列成数组的样式:

a:4:
{
i:0;s:3:"abc";
i:1;s:3:"def";
i:2;s:3:"xyz";
i:3;s:3:"123";
}

这样排列就比较清晰了,看开始的字符串:a:4:{...} 首先第一个字符a保存的是变量类型是array(数组)类型,第二个 4 保存的是数组元素的个数,一共有4个,然后在{}之间数组元素的内容。比如第一个数组元素:i:0;s:3:"abc"; i代表是当前数组元素的索引值类型是整型,并且值是 0,元素值的类型是s(字符串的),个数是 3 个,具体值是"abc",分号结束,下面的数组元素依次类推。

我们再看看使用字符串做为元素索引会如何:

$var = array("index1"=>"abc", "index2"=>"def", "index3"=>"xyz", "index4"=>"123");
echo serialize($var);

输出:

a:4:{s:6:"index1";s:3:"abc";s:6:"index2";s:3:"def";s:6:"index3";s:3:"xyz";s:6:"index4";s:3:"123";}

变成数组样式后:

a:4:
{
 s:6:"index1";s:3:"abc";
 s:6:"index2";s:3:"def";
 s:6:"index3";s:3:"xyz";
 s:6:"index4";s:3:"123";
}

其实跟上面没有太大区别,不过是开始的索引变成了保存字符串的形式,比如第一个元素:s:6:"index1";s:3:"abc";第一项就是索引值:s:6:"index1"; s是类型,6是索引字符串的长度,"index1"就是索引的值。后面的s:3:"abc"; 就是元素值,这个好理解,就不讲了。

从上面来看,我们大致了解了基本数据类型的串行化,其实我们完全可以构造自己的串行化功能,或者从这个角度去扩展,开发自己的串行化程序,便于我们的变量交换。

当然,其实我们也可以利用这个功能,把数组或者任意其他变量串行化成字符串,然后通过curl功能来模拟GET/POST功能,达到能够无用用户执行动作就从远程服务器获取数据的功能。

二、对象序列化

对象的序列化也是一个比较普遍的功能,能够把一个对象进行串行化以后变成一个字符串,能够保存或者传输。

我们先看一个例子:

class TestClass
{
 var $a;
 var $b;

 function TestClass()
 {

$this->a = "This is a";

$this->b = "This is b";
 }

 function getA()
 {

return $this->a;
 }

 function getB()
 {

return $this->b;
 }
}

$obj = new TestClass;
$str = serialize($obj);
echo $str;

输出结果:

O:9:"TestClass":2:{s:1:"a";s:9:"This is a";s:1:"b";s:9:"This is b";}

我们来分析一个对象串行化之后的字符串。

O:9:"TestClass":2:
{
 s:1:"a";s:9:"This is a";
 s:1:"b";s:9:"This is b";
}

首先看对于对象本身的内容:O:9:"TestClass":2:O是说明这是一个对象类型(object),然后9是代表对象的名字查过浓度,2是代表该对象有几个属性。在看两个属性的内容:

s:1:"a";s:9:"This is a"; 其实跟数组的内容比较类似,第一项:s:1:"a"; 是描述属性名称的,第二项s:9:"This is a"; 是描述属性值的。后面的属性类似。

先说一种对象序列化的应用,下面的内容是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:
class A
{
 var $one = 1;

 function show_one()
 {

echo $this->one;
 }
}

// page1.php:
include("classa.inc");

$a = new A;
$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();
?>

如果在用会话并使用了 session_register() 来注册对象,这些对象会在每个 PHP 页面结束时被自动序列化,并在接下来的每个页面中自动解序列化。基本上是说这些对象一旦成为会话的一部分,就能在任何页面中出现。

强烈建议在所有的页面中都包括这些注册的对象的类的定义,即使并不是在所有的页面中都用到了这些类。如果没有这样做,一个对象被解序列化了但却没有其类的定义,它将失去与之关联的类并成为 stdClass 的一个对象而完全没有任何可用的函数,这样就很没有用处。

因此如果在以上的例子中 $a 通过运行 session_register("a") 成为了会话的一部分,应该在所有的页面中包含 classa.inc 文件,而不只是page1.php 和 page2.php。

当然,其实序列化对象其实完全可以应用在很多地方。当然,在PHP 5中对序列化的处理不一样了,我们看一下手册中的说法:

serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。

使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。

相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。

使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

PHP 相关文章推荐
PHP模板引擎Smarty的缓存使用总结
Apr 24 PHP
解决PhpMyAdmin中导入2M以上大文件限制的方法分享
Jun 06 PHP
PHP类的反射用法实例
Nov 03 PHP
php实现将任意进制数转换成10进制的方法
Apr 17 PHP
Yii视图操作之自定义分页实现方法
Jul 14 PHP
深入理解PHP JSON数组与对象
Jul 19 PHP
swoole和websocket简单聊天室开发
Nov 18 PHP
自写的利用PDO对mysql数据库增删改查操作类
Feb 19 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
Sep 28 PHP
php微信公众号开发之答题连闯三关
Oct 20 PHP
Laravel 创建指定表 migrate的例子
Oct 09 PHP
PHP日期和时间函数的使用示例详解
Aug 06 PHP
Windows下的PHP5.0安装配制详解
Sep 05 #PHP
PHP.MVC的模板标签系统(五)
Sep 05 #PHP
PHP.MVC的模板标签系统(四)
Sep 05 #PHP
PHP.MVC的模板标签系统(三)
Sep 05 #PHP
PHP.MVC的模板标签系统(二)
Sep 05 #PHP
PHP.MVC的模板标签系统(一)
Sep 05 #PHP
apache+mysql+php+ssl服务器之完全安装攻略
Sep 05 #PHP
You might like
php事务处理实例详解
2014/07/11 PHP
thinkPHP3.x常量整理(预定义常量/路径常量/系统常量)
2016/05/20 PHP
针对多用户实现头像上传功能PHP代码 适用于登陆页面制作
2016/08/17 PHP
thinkPHP5.0框架独立配置与动态配置方法
2017/03/17 PHP
php在linux环境中如何使用redis详解
2020/12/15 PHP
javascript下判断一个对象是否具有指定名称的属性的的代码
2010/01/11 Javascript
小议Javascript中的this指针
2010/03/18 Javascript
Jquery上传插件 uploadify v3.1使用说明
2012/06/18 Javascript
P3P Header解决Cookie跨域的问题
2013/03/12 Javascript
jQuery让控件左右移动的三种实现方法
2013/09/08 Javascript
浅析js中的浮点型运算问题
2014/01/06 Javascript
javascript父、子页面交互技巧总结
2014/08/08 Javascript
在浏览器中实现图片粘贴的jQuery插件-- pasteimg使用指南
2014/12/29 Javascript
如何动态加载外部Javascript文件
2015/12/02 Javascript
JavaScript从数组的indexOf()深入之Object的Property机制
2016/05/11 Javascript
防止Node.js中错误导致进程阻塞的办法
2016/08/11 Javascript
微信小程序 教程之注册页面
2016/10/17 Javascript
bootstrapValidator 重新启用提交按钮的方法
2017/02/20 Javascript
css和js实现弹出登录居中界面完整代码
2017/11/26 Javascript
vue中英文切换实例代码
2020/01/21 Javascript
[01:10:02]IG vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
Python函数的周期性执行实现方法
2016/08/13 Python
Pycharm技巧之代码跳转该如何回退
2017/07/16 Python
Python中用post、get方式提交数据的方法示例
2017/09/22 Python
pycharm+PyQt5+python最新开发环境配置(踩坑)
2019/02/11 Python
python通过文本在一个图中画多条线的实例
2020/02/21 Python
Python 爬取必应壁纸的实例讲解
2020/02/24 Python
领先的荷兰线上超市:荷兰之家Holland at Home(支持中文)
2021/01/21 全球购物
酒店保洁主管岗位职责
2013/11/28 职场文书
2015年幼儿园毕业感言
2014/02/12 职场文书
庆祝教师节标语
2014/10/09 职场文书
领导干部作风整顿个人剖析材料
2014/10/11 职场文书
交警正风肃纪剖析材料
2014/10/29 职场文书
就业推荐表导师评语
2014/12/31 职场文书
图书馆义工感想
2015/08/07 职场文书
react 路由Link配置详解
2021/11/11 Javascript