1. 串行化的基础认识: 是指将一个变量(包括对象)转换成字节流的过程。串行化有效的解决了对象的保存和传输的问题.例如,如果在用session并使用了 session_register() 来注册对象,这些对象会在每个 PHP 页面结束时被自动序列化,并在接下来的每个页面中自动解序列化,这样在每个PHP页面中都可以使用这些对象。PHP为我们提供了两个函数,用来进行串行化和反串行化的操作,这两个函数分别是:serialize()和unserialize()。serialize()可以处理除资源指针之外的所有类型,该函数返回一个可以被存储在任何地点的字节流表达式的字符串。
<?php
//整型
$var = 23;
echo serialize($var).”\n”; //i:23;
//浮点型
$var = 1.23;
echo serialize($var).”\n”; //d:1.229999999999999982236431605997495353221893310546875;
//字符串
$var = “This is a string”;
echo serialize($var).”\n”; //s:16:”This is a string”;
//布尔型
$var = true;
echo serialize($var).”\n”; //b:1;
//数组变量
$var = array(“abc”, “def”, “xyz”, “123″);
echo serialize($var).”\n”; //a:4:{i:0;s:3:”abc”;i:1;s:3:”def”;i:2;s:3:”xyz”;i:3;s:3:”123″;}
$var = array(“index1″=>”abc”, “index2″=>”def”, “index3″=>”xyz”, “index4″=>”123″);
echo serialize($var).”\n”; //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″;}
//对象序列化
class A
{
public $a = “a string”;
public $b = 123;
public $c = 123.12;
}
$obj = new A;
$str = serialize($obj);
echo $str.”\n”; //O:1:”A”:3:{s:1:”a”;s:8:”a string”;s:1:”b”;i:123;s:1:”c”;d:123.1200000000000045474735088646411895751953125;}
$obj2 = unserialize($str); //进行反序列化
var_dump($obj2 == $obj); //bool(true)
?>
2. 在用 unserialize()时需要注意的一个问题: 在一个PHP页面中要 unserialize() 一个对象,需要该页面包含该对象的类的定义。也就是,如果序列化了 page1.php 中类 A 的对象 $a, 要在 page2.php 中将其反序列化重建类 A 的对象 $a,则 page2.php 中必须要出现类 A 的定义。这可以这样实现,将类 A 的定义放在一个包含文件中,并在 page1.php 和 page2.php 都包含此文件。 所以强烈建议在所有的页面中都包括这些注册的对象的类的定义,即使并不是在所有的页面中都用到了这些类。如果没有这样做,一个对象被反序列化了但却没有其类的定义,它将失去与之关联的类并成为 stdClass 的一个对象而完全没有任何可用的函数。(stdClass是一个空类,里面没有属性也没有方法
var_dump(get_class_methods(stdClass));var_dump(get_class_vars(stdClass));)
//classa.inc:
class A
{
var $one = 1;
function show_one()
{
echo $this->one;
}
}
//page1.php:
include(“classa.inc”);
$a = new A;
$s = serialize($a);
$fp = fopen(“store”, “w”); // 将 $s 存放在某处使 page2.php 能够找到
fputs($fp, $s);
fclose($fp);
//page2.php:
include(“classa.inc”); // 为了正常解序列化需要这一行
$s = implode(“”, @file(“store”));
$a = unserialize($s);
$a->show_one(); // 现在可以用 $a 对象的 show_one() 函数了
?>
如果以上的例子中 $a 通过运行 session_register(“a”) 成为了会话的一部分,$a会在该PHP 页面结束时被自动序列化,在其他PHP页面中会自动反序列化从而可以使用该对象,那么应该在所有的页面中包含 classa.inc 文件,而不只是 page1.php 和 page2.php。
3.__sleep() __wakeup()
serialize() 检查类中是否有 __sleep() ,如果有,则该函数将在任何序列化之前运行。该函数必须返回一个需要进行序列化保存的成员属性数组,并且只序列化该函数返回的这些成员属性. 该函数有两个作用: 第一. 在序列化之前,关闭对象可能具有的任何数据库连接等. 第二. 指定对象中需要被序列化的成员属性,如果某个属性比较大而不需要储存下来,可以不把它写进__sleep要返回的数组中,这样该属性就不会被序列化
相反地,unserialize() 从字节流中创建了一个对象之后,马上检查是否具有__wakeup 的函数的存在。如果存在,__wakeup 立刻被调用。使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
<?php
class User
{
public $name;
public $id;
function __construct()
{
$this->id = uniqid(); //give user a unique ID 赋予一个不同的ID
}
function __sleep()
{
return(array(“name”)); //do not serialize this->id 不串行化id
}
function __wakeup()
{
$this->id = uniqid(); //give user a unique ID
}
}
$u = new User;
$u->name = “HAHA”;
$s = serialize($u); //serialize it 串行化 注意不串行化id属性,id的值被抛弃
$u2 = unserialize($s); //unserialize it 反串行化 id被重新赋值
//$u and $u2 have different IDs $u和$u2有不同的ID
var_dump($u);
var_dump($u2);
?>
———- PHP debug ———-
object(User)#1 (2) {
["name"]=>
string(4) “HAHA”
["id"]=>
string(13) “47fa045529f69″
}
object(User)#2 (2) {
["name"]=>
string(4) “HAHA”
["id"]=>
string(13) “47fa04552a49a”
}
输出完成 (耗时: 0 秒) – 正常终止