PHP序列化与反序列化学习

<h6>序列化与反序列化学习</h6>
<p>把对象转换为字节序列的过程称为对象的序列化;把字节序列恢复为对象的过程称为对象的反序列化。</p>
<pre><code>&lt;?php

class UserInfo  {

    public $name = &quot;admin&quot;;

    public $age = 1;

    public $blog = &quot;file:///var/www/html/flag.php&quot;;

}

$data = new UserInfo();

echo serialize($data);

?&gt;
</code></pre>

<p>页面显示:<br />
<code>O:8:&quot;UserInfo&quot;:3:{s:4:&quot;name&quot;;s:5:&quot;admin&quot;;s:3:&quot;age&quot;;i:1;s:4:&quot;blog&quot;;s:29:&quot;file:///var/www/html/flag.php&quot;;}</code> <br />
此处调用到了serialize函数,对数据进行了序列化并返回了一组字符串。  
</p>
<pre><code>&lt;?php
$sites = array(‘t1‘, ‘tt2‘, ‘ttt3‘);
$serialized_data = serialize($sites);
echo  $serialized_data;
?&gt;
</code></pre>

<p>输出:<code>a:3:{i:0;s:2:&quot;t1&quot;;i:1;s:3:&quot;tt2&quot;;i:2;s:4:&quot;ttt3&quot;;}</code>
对这个序列化的输出进行分析:  
</p>
<pre><code>a:3表示数组里面有三个分类。
i:0:表示第一个数组。  
s:2:表示有两个字符
&quot;t1&quot;:表示内容为‘t1‘。

i:1:表示第二个数组。
s:3:&quot;tt2&quot;:标识有三个字符,内容为‘tt2‘
</code></pre>

<p>反序列化:
    &lt;?php
    $sites = array(‘t1‘, ‘tt2‘, ‘ttt3‘);
    $serialized<em>data = serialize($sites);
    #echo  $serialized</em>data;
    $unserialized<em>data = unserialize($serialized<em>data);
    print</em>r($unserialized</em>data);
    ?&gt;</p>
<p>此时又生成回:<code>Array ( [0] =&gt; t1 [1] =&gt; tt2 [2] =&gt; ttt3 )</code>   
</p>
<p>其中:o表示对象,a表示数组,s表示字符,i表示数字</p>
<h4>类</h4>
<p>在php中,一个类可以包含有属于自己的常量,变量(属性)以及函数(方法)<br />
一段反序列化,序列化代码:(来自https://www.jianshu.com/p/8f498198fc3d)</p>
<pre><code>&lt;?php
class Test  
{  
    public $handle1;  
    private $handle2;
    protected $handle3;

    public function __construct($handle1,$handle2,$handle3)  
    {  
        $this-&gt;handle1 = $handle1;
        $this-&gt;handle2 = $handle2;
        $this-&gt;handle3 = $handle3;
        echo ‘__construct&lt;br /&gt;‘;  
    }  
    public function __destruct()  
    {  
        echo $this-&gt;handle2.‘&lt;br /&gt;‘;
        echo ‘__destruct&lt;br /&gt;‘;
    }  
    public function __wakeup()  
    {  
        echo ‘__wakeup&lt;br /&gt;‘;
    }
}

$obj = new Test(&quot;111&quot;,&quot;222&quot;,&quot;333&quot;);
$see = serialize($obj);
print ‘Serialized: ‘ . $see . ‘&lt;br /&gt;‘;
# %00Test%00v2 表示 private      %00*%00v3 表示protected
$ss = ‘O:4:&quot;Test&quot;:3:{s:7:&quot;handle1&quot;;s:3:&quot;777&quot;;s:17:&quot;%00Test%00handle2&quot;;s:3:&quot;888&quot;;S:14:&quot;%00*%00handle3&quot;;s:3:&quot;999&quot;;}‘;
$obj2 = unserialize($ss);
var_dump($obj2);

?&gt;  
</code></pre>

<p>在这段php代码中:<br />
<code>$obj = new Test(&quot;111&quot;,&quot;222&quot;,&quot;333&quot;);</code>创建了类的实例,所以使用到了new的关键字。</p>
<p>在类中对于静态方法和静态属性的引用:  
</p>
<pre><code>class Test{
public static $test = 1;
public static function test(){
  }
}
</code></pre>

<p>此时我们不用实例化对象,直接使用Test::$test就能获取$test属性的值,Test::test()这样可以直接调用静态方法test。  
</p>
<p>范围解析操作符:可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法,即<code>::</code></p>
<pre><code>&lt;?php
class MyClass {
    const CONST_VALUE = ‘A constant value‘;
}

$classname = ‘MyClass‘;
echo $classname::CONST_VALUE; // 自 PHP 5.3.0 起
echo ‘&lt;br&gt;‘;
echo MyClass::CONST_VALUE;
?&gt;
</code></pre>

<p>此时我们就使用了变量静态地调用了类MyClass当中的常量,注意自 PHP 5.3.0 起,可以通过变量来引用类,但该变量的值不能是关键字。<br />
结果:  
</p>
<pre><code>A constant value
A constant value
</code></pre>

<p>使用子类覆盖父类:</p>
<pre><code>&lt;?php
class OtherClass extends MyClass
{
    public static $my_static = ‘static var‘;

    public static function doubleColon() {
        echo parent::CONST_VALUE . &quot;\n&quot;;
        echo self::$my_static . &quot;\n&quot;;
    }
}

$classname = ‘OtherClass‘;
echo $classname::doubleColon(); // 自 PHP 5.3.0 起

OtherClass::doubleColon();
?&gt;
</code></pre>

<p>此时PHP不会调用父类中已被覆盖的方法,是否调用父类的方法取决于子类。</p>
<p>调用父类方法:</p>
<pre><code>&lt;?php
class MyClass
{
    protected function myFunc() {
        echo &quot;MyClass::myFunc()\n&quot;;
    }
}

class OtherClass extends MyClass
{
    // 覆盖了父类的定义
    public function myFunc()
    {
        // 但还是可以调用父类中被覆盖的方法
        parent::myFunc();
        echo &quot;OtherClass::myFunc()\n&quot;;
    }
}

$class = new OtherClass();
$class-&gt;myFunc();
?&gt;
</code></pre>

<p>输出:<br />
<code>MyClass::myFunc() OtherClass::myFunc()</code><br />
其中-&gt; 是对象成员访问符号。<br />
例如:<code>$this-&gt;name = $value</code><br />
其中:$this是特定变量,它代表了他的类,通过-&gt;我们可以访问其类的成员,所以这段代码的意思就是:将当前类的name变量的值设置为 $value. </p>
<p>继承:类可以在声明中用 extends 关键字继承另一个类的方法和属性。PHP不支持多重继承,一个类只能继承一个基类。  
</p>
<pre><code>class Father
{
    public $aar;

    public function bar ()
    {
        return ‘father‘;
    }

    final public function testFinal ()
    {
        return ‘father‘;
    }

}
class Son extends father
{
    public function bar ()
    {
        return ‘son‘;
    }

    public function callFatherBar ()
    {
        return parent::bar();
    }
    //Cannot override final method Father::testFinal()
    // public function testFinal()
    // {

    // }
    //如果父类定义是设置了final 则父类方法均不能覆盖 final class Father
    //属性无final的概念
}
echo (new Son())-&gt;bar();//son
echo (new Son())-&gt;callFatherBar();//father  
</code></pre>

<p>前面写类方法获取属性我们使用的是<code>::</code>这是在静态环境中,对于非静态的,我们使用$this-&gt;property即可。<br />
属性的声明由关键词:public,protected或者private开头,后面加上变量。<br />
即:  
</p>
<pre><code>public $handle1;  
private $handle2;
protected $handle3;
</code></pre>

<p>我们声明了三个不同属性的变量:</p>
<p>三个关键字控制 public 公有;protected 受保护;private 私有的</p>
<pre><code>public:可以在任何地方被访问

protected:可以被自身或其子类和父类访问,表示方式是在变量名前加上%00类名%00

private:只能被其定义所在的类访问,表示方式是在变量名前加个%00*%00
</code></pre>

<p>还有关于常量的定义:<br />
<code>const constant = ‘constant value‘;</code></p>
<h6>构造函数</h6>
<p>在PHP5中,可以在一个类中定义一个构造函数,具有构造函数的类,当每次创建新的对象的时候会先调用这个方法,以方便我们在使用对象前做一些初始化工作。  
</p>
<pre><code>class Father
{
     function __construct ()//不可为private
    {
        echo ‘Father‘;
    }
}

class Child extends Father
{    //当Child无构造函数时,自动调用父类的 Father
    function __construct ()
    {
        echo ‘Child‘;
    }

    function callFatherConstruct ()
    {
        parent::__construct();
    }
}

$obj = new Child;//Child

$obj-&gt;callFatherConstruct();//Father
</code></pre>

<p>子类中定义了构造函数,不会隐式的调用父类的构造函数,需要用parent::__construct()调用,如果子类没有构造函数,父类的构造函数将和普通函数一样被子类继承。</p>
<p>参考链接:<a href="https://www.cnblogs.com/ValleyUp/p/11181141.html">https://www.cnblogs.com/ValleyUp/p/11181141.html</a></p>
<h6>magic函数</h6>
<p>php类包含magic函数的特殊函数,magic函数命名是以符号 __ 开头的,例如 __ sleep, __  wakeup,__ construct,  __ destruct等。<br />
这些函数经常会被自动调用,<strong>construct当一个对象创建时被调用,</strong>destruct当一个对象销毁时被调用。<br />
常用的魔术方法有:  
</p>
<pre><code>serialize():检查类中是否存在一个魔术方法 __sleep(),优先调用此方法,然后执行序列化操作。
unserialize():检查是否存在一个 __wakeup() 方法,优先调用此方法
__construct():当一个对象创建时被调用
__destruct():当一个对象销毁时被调用
__call():当调用一个未定义(包括没有权限访问)的方法是调用此方法
__callStatic():处理静态方法调用
__get():当调用一个未定义的属性时访问此方法
__set(): 给一个未定义的属性赋值时调用
__isset():当在一个未定义的属性上调用isset()函数时调用此方法
__unset():当在一个未定义的属性上调用unset()函数时调用此方法
__sleep():常用于提交未提交的数据,或类似的清理操作,在对象被序列化之前运行
__wakeup():用于预先准备对象需要的资源,在对象被反序列化之后被调用
__toString():用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串
__invoke():当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
__set_state(),:当调用var_export()时,这个静态 方法会被调用(自PHP 5.1.0起有效)。本方法的唯一参数是一个数组,其中包含按array(’property’ =&gt; value, …)格式排列的类属性。
__clone() :对象赋值时使用的引用赋值,使用clone方法复制一个对象时,对象会自动调用__clone魔术方法
</code></pre>

<p>当序列化字符串中,表示对象属性个数的值大于实际属性个数时,那么就会跳过wakeup方法的执行。<br />
拿php一个代码为例,综合上面学习的进行理解:</p>
<pre><code>&lt;?php
class Connection   //定义一个类,类名为Connection
{
    protected $link;    //定义一个变量属性,可以被自身或其子类和父类访问
    private $server, $username, $password, $db;   //定义了四个变量属性,只能被其定义所在的类访问。

    public function __construct($server, $username, $password, $db)    //定义一个方法,可以在任何地方被访问
    {
        $this-&gt;server = $server;             //$this是特定变量,它代表了他的类connection,通过-&gt;我们可以访问其类的成员如server等,将当前类的server变量的值设置为 $server.
        $this-&gt;username = $username;         //同上,以下皆是。
        $this-&gt;password = $password;
        $this-&gt;db = $db;
        $this-&gt;connect();
    }

    private function connect()  //定义一个方法,只能被其定义所在的类访问
    {
        $this-&gt;link = mysql_connect($this-&gt;server, $this-&gt;username, $this-&gt;password);    //当前的link,用来连接mysql数据库。
        mysql_select_db($this-&gt;db, $this-&gt;link);
    }

    public function __sleep()     //提交数据时,要进行的行为。
    {
        return array(‘server‘, ‘username‘, ‘password‘, ‘db‘);     //提交的时候返回
    }

    public function __wakeup()     //重新建立数据库连接
    {
        $this-&gt;connect();
    }
}
?&gt;
</code></pre>

<p>序列化得到字符串格式:  
</p>
<pre><code>s:size:value:表示字符。  
a:size:{键值;值;元素},
例如a:3:{i:0;s:2:&quot;t1&quot;;i:1;s:3:&quot;tt2&quot;;i:2;s:4:&quot;ttt3&quot;;}  
i:0,表示第一个数组,s:2表示有两个字符,&quot;t1&quot;,表示字符为t1。
O:对象长度:对象类名称:成员变量数:{类型:字符个数长度:&quot;具体值&quot;;类型:长度:&quot;具体值&quot;;.......}  
O:4:&quot;Test&quot;:3:{s:7:&quot;handle1&quot;;s:3:&quot;111&quot;;s:13:&quot;Testhandle2&quot;;s:3:&quot;222&quot;;s:10:&quot;*handle3&quot;;s:3:&quot;333&quot;;}
O:1:&quot;A&quot;:2:{s:6:&quot; A var&quot;;i:1139586461;s:4:&quot;var2&quot;;s:1:&quot;b&quot;;}
</code></pre>

<p>反序列化能将类的成员变量还原,但是不能将类的方式还原。<br />
解析顺序:<br />
<img src="https://image.3001.net/images/20190731/1564545530_5d4111fa958d0.png!small" /></p>
<h6>json<em>encode/json</em>decode</h6>
<pre><code>&lt;?php
$a=array(‘a‘=&gt;‘cuit‘,‘b‘=&gt;‘syclover‘,‘c‘=&gt;‘dog‘);
//序列化数组
$s=json_encode($a);
echo $s;
//反序列化
$o=json_decode($s);
?&gt;
</code></pre>

<p>输出:<code>{&quot;a&quot;:&quot;cuit&quot;,&quot;b&quot;:&quot;syclover&quot;,&quot;c&quot;:&quot;dog&quot;}</code></p>

相关推荐