PHP教程

PHP反序列化

本文主要是介绍PHP反序列化,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、前置知识

1、基本概念

类定义是以关键字 class 开头,后跟类的名称。类的主体是包含在一对花括号中,里面有类的属性与方法的定义。

类属性存在于数据段,类方法存在于代码段,对于一个类来说,类的方法不占用类的空间,占空间的只有类的属性。

2、语法

要创建一个类的实例,必须使用 new 关键字。当创建新对象时该对象总是被赋值,除非该对象定义了构造函数并且在出错时抛出了一个异常。类应在被实例化之前定义(某些情况下则必须这样)。

如果在 new 之后跟着的是一个包含有类名的字符串,则该类的一个实例被创建。如果该类属于一个名字空间,则必须使用其完整名称。

//创建一个实例
<?php
$instance = new SimpleClass();

// 也可以这样做:
$className = 'Kin';
$instance = new $className(); // Kin()
?>

二、序列化

如果一个脚本中想要调用之前一个脚本的变量,但是前一个脚本已经执行完毕,所有的变量和内容释放掉了,我们要如何操作呢?

serialize和unserialize就是解决这一问题的存在,serialize可以将变量转换为字符串,并且在转换中可以保存当前变量的值;而unserialize则可以将serialize生成的字符串变换回变量。

1、serialize()

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。

 可以这么理解:

在程序执行结束时,内存数据便会立即销毁,变量所储存的数据便是内存数据,而文件、数据库是“持久数据”,因此 PHP序列化就是将内存的变量数据“保存”到文件中的持久数据的过程。

 

举个栗子:

<?php
class User
{
  public $age = 0;
  public $name = ''; 
  public function PrintData()
  {
    echo 'User '.$this->name.' is'.$this->age.' years old. <br />';
  }
}

//创建一个对象
$user = new User();

// 设置数据
$user->age = 17;
$user->name = 'kinyoobi';

//输出数据
$user->PrintData();

//输出序列化之后的数据
echo serialize($user);
?>

结果:

O 表示对象类型,4 表示对象名长度为4,User 为类名,2 表示有两个参数;

{} 里面是参数的key和value:s 表示是string类型,3 表示长度,age 是key;i 表示是integer类型,17 是value。

a array b boolean
d
double i integer
o common object r reference
s string C custom object
O class N null
R pointer reference U unicode string

2、unserialize()

反序列化就是将序列化格式化存储好的的字符还原成对象的过程。

注意:在解序列化一个对象前,这个对象的类必须在解序列化之前定义。否则会报错

 

举个栗子:

<?php
class User
{
  public $age = 0;
  public $name = '';
  public function PrintData()
  {
    echo 'User '.$this->name.' is '.$this->age.' years old. <br />';
  }
}
//重建对象
$user = unserialize('O:4:"User":2:{s:3:"age";i:17;s:4:"name";s:8:"kinyoobi";}');
$user->PrintData();
?>

结果:

3、魔术方法

PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法,在特定的情况下会被调用。

__construct  构造函数
__destruct 对象被销毁时触发,析构函数
__toString 把类当作字符串使用时触发
__wakeup() unserialize前调用,用于预先准备对象资源
__sleep()  serialize前调用
__call() 在对象上下文中调用不可访问的方法时触发
__callStatic()  在静态上下文中调用不可访问的方法时触发
__get()  试图读取一个并不存在的属性的时候被调用
__set()  用于将数据写入不可访问的属性
__isset() 在不可访问的属性上调用isset()或empty()触发
__unset()  在不可访问的属性上使用unset()时触发
__invoke() 脚本尝试将对象调用为函数时触发

4、与序列化相关的两个魔术方法

1)__sleep()

serialize()函数会检查类中是否存在一个魔术方法 __sleep()。如果存在__sleep(),该魔术方法会先被调用,然后才执行序列化操作。

此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

2)__wakeup()

unserialize()函数会检查是否存在一个 __wakeup()方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。

__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

 

举个栗子:

<?php
 class test{
 public $varr1="abc";
 public $varr2="123";
 
 public function echoP(){
 echo $this->varr1."<br>";
 }

 public function __construct(){
 echo "__construct<br>";
 }

 public function __destruct(){
 echo "__destruct<br>";
 }

 public function __toString(){
 return "__toString<br>";
 }

 public function __sleep(){
 echo "__sleep<br>";
 //return array('varr1','varr2');
 return array('varr1');
 }

 public function __wakeup(){
 echo "__wakeup<br>";
 }
}

$obj = new test();  //实例化对象,调用__construct()方法,输出__construct
$obj->echoP();  //调用echoP()方法,输出"abc"
echo $obj;  //obj对象被当做字符串输出,调用__toString()方法,输出__toString
$s =serialize($obj);  //obj对象被序列化,调用__sleep()方法,输出__sleep
var_dump($s);
echo "<br>";
$u = unserialize($s);  //$s首先会被反序列化,会调用__wake()方法
var_dump($u);
echo "<br>";
// 脚本结束又会调用__destruct()方法,输出__destruct

?>

结果:

其中在序列化时,__sleep返回了varr1,达到了清理数据的目的;而在反序列化时,即类恢复成对象的时候,类本身的类属性是不能被销毁的,所以最后会打印出来varr1和varr2。

 

 参考:

https://www.cnblogs.com/ichunqiu/p/10484832.html

https://www.php.cn/php-weizijiaocheng-454909.html

 

这篇关于PHP反序列化的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!