今天突然看到一本书上讲的是序列化,挺感兴趣的研究了一下,贴一下研究成果
,首先上测试代码:
分别测试了序列化和json_encode对对象和数组的编码测试,如下:
<?php
class person
{
protected $name='张三';
protected $age=22;
protected $job='admin';
public function say()
{
echo '这是对象说的一句话';
}
}
$arr=array(
'name'=>'李四',
'age'=>25,
'job'=>'student'
);
$per=new person();
$obj=serialize($per);
echo '---------------------序列化对象-----------------------'.PHP_EOL;
echo ($obj).PHP_EOL;
echo PHP_EOL;
echo '---------------------反序列化对象-----------------------'.PHP_EOL;
var_dump(unserialize($obj)).PHP_EOL;
echo PHP_EOL;
echo '---------------------序列化数组-----------------------'.PHP_EOL;
var_dump($arr).PHP_EOL;
echo PHP_EOL;
echo '---------------------json串化数组-----------------------'.PHP_EOL;
echo $narr=json_encode($arr).PHP_EOL;
echo PHP_EOL;
echo '---------------------json反串化数组-----------------------'.PHP_EOL;
var_dump(json_decode($narr)).PHP_EOL;
echo PHP_EOL;
echo '---------------------json串化对象-----------------------'.PHP_EOL;
var_dump(json_encode($per)).PHP_EOL;
echo PHP_EOL;
?>
结果如下:
---------------------序列化对象-----------------------
O:6:"person":3:{s:7:"*name";s:6:"张三";s:6:"*age";i:22;s:6:"*job";s:5:"admin";}
---------------------反序列化对象-----------------------
class person#2 (3) {
protected $name =>
string(6) "张三"
protected $age =>
int(22)
protected $job =>
string(5) "admin"
}
---------------------序列化数组-----------------------
array(3) {
'name' =>
string(6) "李四"
'age' =>
int(25)
'job' =>
string(7) "student"
}
---------------------json串化数组-----------------------
{"name":"\u674e\u56db","age":25,"job":"student"}
---------------------json反串化数组-----------------------
class stdClass#2 (3) {
public $name =>
string(6) "李四"
public $age =>
int(25)
public $job =>
string(7) "student"
}
---------------------json串化对象-----------------------
string(2) "{}"
在这里要说说序列化的最重要的魔术方法 __sleep()和__wakeup(),也是和json编码有实质区别的地方。
还是举例说明:
<?php
class test
{
public $a=1;
public $b=2;
public function __sleep()
{
return ['a','b'];
}
public function __wakeup()
{
echo $this->a.PHP_EOL;
}
}
$test=new test();
unserialize(serialize($test));
//cli结果
localhost:test yehua$ php func.php
1
localhost:test yehua$
解释一下上面的例子,当执行类的序列化的同时,系统会自动调用sleep函数 保存当前返回数据里面的值,这些值可以是当前类属性的值,可以理解为冻结。当序列化解除的时候 系统会调用wakeup 通过该函数可以让类继续工作 ,可以理解为苏醒。我看也来看看苏醒之后能做什么
<?php
class test
{
public $a=1;
private $v=2;
public static $c=3;
const D=4;
public function write()
{
echo 'write code'.PHP_EOL;
}
public static function speak()
{
echo 'speaking'.PHP_EOL;
}
public function __sleep()
{
return ['a','v','c','D'];
}
public function __wakeup()
{
self::speak();
$this->write();
}
}
$test=new test();
var_dump($res=serialize($test)).PHP_EOL;
echo '-------------------------'.PHP_EOL;
var_dump(unserialize($res)).PHP_EOL;
//cli 结果
localhost:test yehua$ php func.php
/Users/yehua/Desktop/test/func.php:29:
string(65) "O:4:"test":4:{s:1:"a";i:1;s:7:"\000test\000v";i:2;s:1:"c";N;s:1:"D";N;}"
-------------------------
speaking
write code
/Users/yehua/Desktop/test/func.php:31:
class test#2 (4) {
public $a =>
int(1)
private $v =>
int(2)
public $c =>
NULL
public $D =>
NULL
}
苏醒之后可以调用自身的方法。如果我们有类似冻结-苏醒这种需求可以试试
我们再看看更多情况下的序列化表现
<?php
class test
{
//普通变量
public $a=1;
//私有变量
private $v=2;
//静态变量
public static $c=3;
//常量
const D=4;
//公共方法
public function write()
{
echo 'write code';
}
//静态方法
public static function speak()
{
echo 'speaking';
}
}
$test=new test();
var_dump($res=serialize($test)).PHP_EOL;
echo '-------------------------';
var_dump(unserialize($res)).PHP_EOL;
// cli 结果
/Users/yehua/Desktop/test/func.php:23:
string(45) "O:4:"test":2:{s:1:"a";i:1;s:7:"\000test\000v";i:2;}"
-------------------------/Users/yehua/Desktop/test/func.php:25:
class test#2 (2) {
public $a =>
int(1)
private $v =>
int(2)
}
测试完毕之后发现,序列化只保存常规变量;
我们再试试继承
<?php
class test
{
public $a=1;
private $v=2;
}
class T extends test
{
}
$test=new T();
var_dump($res=serialize($test)).PHP_EOL;
echo '-------------------------'.PHP_EOL;
var_dump(unserialize($res)).PHP_EOL;
//cli结果
/Users/yehua/Desktop/test/func.php:13:
string(42) "O:1:"T":2:{s:1:"a";i:1;s:7:"\000test\000v";i:2;}"
-------------------------
/Users/yehua/Desktop/test/func.php:15:
class T#2 (2) {
public $a =>
int(1)
private $v =>
int(2)
}
看来单继承是没有问题的,我们再试试多继承
<?php
class test
{
public $a=1;
private $v=2;
}
trait testb
{
public $c=2;
}
class T extends test
{
use testb;
}
$test=new T();
var_dump($res=serialize($test)).PHP_EOL;
echo '-------------------------'.PHP_EOL;
var_dump(unserialize($res)).PHP_EOL;
// 结果
string(54) "O:1:"T":3:{s:1:"a";i:1;s:7:"\000test\000v";i:2;s:1:"c";i:2;}"
-------------------------
/Users/yehua/Desktop/test/func.php:19:
class T#2 (3) {
public $a =>
int(1)
private $v =>
int(2)
public $c =>
int(2)
}
也是没问题的
总结一下:
序列化可以同时实现对对象和数组实现保存,更重要的是,序列化不同于json编码,他还保存数据的类型。*注意下只能保存对象的属性,不能保存方法。
json_encode 可以保存数组,但是不能保存对象。而且反编码之后不会恢复原有数据结构
因此,序列化在redis 和数据库中有很大的作用 可以很好的保存数据和类型。更重要的是保存状态。是一种临时冻结的策略。
*最后提一下速度问题。序列化的速度大概比json_encode 慢一倍左右。