直击PHP序列化和反序列化道理
0.前言
对象的序列化和反序列化作用就不再赘述,php中序列化的结果是一个php自定义的字符串格局,有点相似json.
我们在任何说话中设计对象的序列化和反序列化都需要解决几个问题
把某个对象序列化之后,序列化的结果有自描写的功效(从序列化的结果中知道这个对象的详细类型,
知道类型还不足,当然还需要知道这个类型所对应详细的值).
序列化时的权限操纵,可以自定义序列化字段等,例如golang中的做的就非常利便.
时间机能问题:在某些机能敏锐的场景下,对象序列化就不克不及拖后腿,例如:高机能效劳(我经常使用protobuf来序列化).
空间机能问题:序列化之后的结果不克不及太长,比方内存中一个int对象,序列化之后数据长度变成了10倍int的长度,那这个序列化算法是有问题的.
本文仅仅从php代码角度来说明php中序列化和反序列化的历程.,记住一点序列化和反序列化操纵的仅仅是对象的数据,这一点有面向对象开发经历的都应当容易懂得.
相关学习引荐: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序列化和反序列化道理的具体内容,更多请关注百分百源码网其它相关文章!