温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

PHP中序列化与反序列化的原理是什么

发布时间:2021-01-14 16:03:25 来源:亿速云 阅读:163 作者:Leah 栏目:开发技术

这篇文章给大家介绍PHP中序列化与反序列化的原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

1.序列化serialize和反序列化方法unserialize

php原生提供了对象序列化功能,不像c++ ……^_^. 用起来也非常简单,就两个接口.

class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj); //通过serialize接口序列化
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);//通过unserialize反序列化
$toobj->print();
fobnn
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:16:"fobnnhack_name";s:5:"fobnn";}
fobnn

看到第二行的输出,这个字符串就是序列化的结果,这个结构其实很容读懂,可以发现是通过对象名称/成员名称来映射的,当然不同访问权限的成员序列化之后的标签名称略有不同.

根据我上面讲到的3个问题,那么我们可以来看看

1.自描述功能

O:5:"fobnn":2 其中o就表示了object类型,且类型名称为fobnn, 采用这种格式,后面的2表示了有2个成员对象.

关于成员对象,其实也是同一套子描述,这是一个递归的定义.

自描述的功能主要是通过字符串记录对象和成员的名称来实现.

2.性能问题

php序列化的时间性能本文就不分析了,详见后面,但序列化结果其实类似json/bson定义的协议,有协议头,协议头说明了类型,协议体则说明了类型所对应的值,并不会对序列化结果进行压缩.

2.反序列化中的魔术方法

对应上述说的第二个问题,其实php中也有解决方法,一种是通过魔术方法,第二种则是自定义序列化函数.先来介绍下魔术方法 __sleep和__wakeup

class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
 public function __sleep()
 {
  return array("hack_name");
 }
 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
fobnn
O:5:"fobnn":1:{s:16:"fobnnhack_name";s:5:"fobnn";}
haha

在序列化之前会先调用__sleep返回的是一个需要序列化的成员名称数组,通过这样我们就可以控制需要序列化的数据,案例中我只返回了hack_name,可以看到结果中只序列化了hack_name成员.

在序列化完成之后,会跳用__wakeup 在这里我们可以做一些后续工作,例如重连数据库之类的.

3.自定义Serializable接口

interface Serializable {
abstract public string serialize ( void )
abstract public void unserialize ( string $serialized )
}

通过这个接口我们可以自定义序列化和反序列化的行为,这个功能主要可以用来自定义我们的序列化格式.

class fobnn implements Serializable
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }

 public function __sleep()
 {
  return array('hack_name');
 }

 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }

 public function serialize()
 {
  return json_encode(array('id' => $this->hack_id ,'name'=>$this->hack_name ));
 }

 public function unserialize($var)
 {
  $array = json_decode($var,true);
  $this->hack_name = $array['name'];
  $this->hack_id = $array['id'];
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
fobnn
C:5:"fobnn":23:{{"id":1,"name":"fobnn"}}
fobnn

当使用了自定义序列化接口之后,我们的魔术方法就没用了.

4.PHP动态类型和PHP反序列化

既然上文中提到的自描述功能,那么序列化结果中保存了对象的类型,且php是动态类型语言,那么我们就可以来做个简单的实验.

class fobnn
{
 public $hack_id;
 public $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  var_dump($this->hack_name);
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
$toobj2 = unserialize("O:5:\"fobnn\":2:{s:7:\"hack_id\";i:1;s:9:\"hack_name\";i:12345;}");
$toobj2->print();

我们修改hack_name反序列化的结果为int类型, i:12345

string(5) "fobnn"
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:9:"hack_name";s:5:"fobnn";}
string(5) "fobnn"
int(12345)

可以发现,对象成功序列化回来了!并且可以正常工作!. 当然php的这种机制提供了灵活多变的语法,但也引入了安全风险. 后续继续分析php序列化和反序列化特性带来的安全问题.

关于PHP中序列化与反序列化的原理是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI