过年了 發表於 2021-7-9 10:45:00

PHP反序列化

<p><span style="font-size: 18pt">1.什么是php序列号和反序列化</span></p>
<p>  </p>
<p><strong>在开发的过程中常常遇到需要把对象或者数组进行序列号存储,反序列化输出的情况。特别是当需要把数组存储到mysql数据库中时,我们时常需要将数组进行序列化操作。</strong></p>
<p><strong>php序列化(serialize):是将变量转换为可保存或传输的字符串的过程</strong></p>
<p><strong>php反序列化(unserialize):就是在适当的时候把这个字符串再转化成原来的变量使用</strong></p>
<p><strong>这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。</strong></p>
<p><strong>常见的php序列化和反序列化方式主要有:serialize,unserialize;json_encode,json_decode。</strong></p>
<p>&nbsp;</p>
<p><span style="font-size: 18pt">2.php类与属性</span></p>
<p><strong>简单写一段php代码,与Java里面的类、对象类似</strong></p>
<p><strong><img src="https://img2020.cnblogs.com/blog/2357704/202107/2357704-20210709104248309-1219117609.png" alt="" loading="lazy"></strong></p>
<p><strong>运行结果:</strong></p>
<p>&nbsp;</p>
<p><strong><strong><img src="https://img2020.cnblogs.com/blog/2357704/202107/2357704-20210709104311098-1717158670.png" alt="" width="560" height="289" loading="lazy"></strong></strong></p>
<p>&nbsp;</p>
<p><span style="font-size: 18pt">3.魔术方法</span></p>
<p><strong><strong><strong><strong>php中有着魔术方法,以两个__下划线开头的方法称为魔术方法。在触发某个事件后,魔术方法会自动调用。</strong></strong></strong></strong></p>
<table border="2" cellpadding="2" align="center">
<tbody>
<tr>
<td>方法名</td>
<td>作用</td>
</tr>
<tr>
<td>__construct</td>
<td>构造函数,在创建对象时候初始化对象,一般用于对变量赋初值</td>
</tr>
<tr>
<td>__destruct</td>
<td>析构函数,和构造函数相反,在对象不再被使用时(将所有该对象的引用设为null)或者程序退出时自动调用</td>
</tr>
<tr>
<td>__toString</td>
<td>当一个对象被当作一个字符串被调用,把类当作字符串使用时触发,返回值需要为字符串,例如echo打印出对象就会调用此方法</td>
</tr>
<tr>
<td>__wakeup()</td>
<td>使用unserialize时触发,反序列化恢复对象之前调用该方法</td>
</tr>
<tr>
<td>__sleep()</td>
<td>使用serialize时触发 ,在对象被序列化前自动调用,该函数需要返回以类成员变量名作为元素的数组(该数组里的元素会影响类成员变量是否被序列化。只有出现在该数组元素里的类成员变量才会被序列化)</td>
</tr>
<tr>
<td>__destruct()</td>
<td>对象被销毁时触发</td>
</tr>
<tr>
<td>__call()</td>
<td>在对象中调用不可访问的方法时触发,即当调用对象中不存在的方法会自动调用该方法</td>
</tr>
<tr>
<td>__callStatic()</td>
<td>在静态上下文中调用不可访问的方法时触发</td>
</tr>
<tr>
<td>__get()</td>
<td>读取不可访问的属性的值时会被调用(不可访问包括私有属性,或者没有初始化的属性)</td>
</tr>
<tr>
<td>__set()</td>
<td>在给不可访问属性赋值时,即在调用私有属性的时候会自动执行</td>
</tr>
<tr>
<td>__isset()</td>
<td>当对不可访问属性调用isset()或empty()时触发</td>
</tr>
<tr>
<td>__unset()</td>
<td>当对不可访问属性调用unset()时触发</td>
</tr>
<tr>
<td>__invoke()</td>
<td>当脚本尝试将对象调用为函数时触发</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><strong>通过触发事件而调用不通的魔术方法</strong></p>
<div class="cnblogs_code">
<pre>&lt;?<span style="color: rgba(0, 0, 0, 1)">php
    </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> animal {
      </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(128, 0, 128, 1)">$name</span> = 'Nolan'<span style="color: rgba(0, 0, 0, 1)">;

      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span> <span style="color: rgba(0, 128, 128, 1)">sleep</span><span style="color: rgba(0, 0, 0, 1)">(){
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "&lt;hr&gt;"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 128, 1)">$this</span>-&gt;name . " is sleeping...\n"<span style="color: rgba(0, 0, 0, 1)">;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> __wakeup(){
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "&lt;hr&gt;"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "调用了__wakeup()方法\n"<span style="color: rgba(0, 0, 0, 1)">;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> __construct(){
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "&lt;hr&gt;"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "调用了__construct()方法\n"<span style="color: rgba(0, 0, 0, 1)">;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> __destruct(){
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "&lt;hr&gt;"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "调用了__destruct()方法\n"<span style="color: rgba(0, 0, 0, 1)">;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> __toString(){
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "&lt;hr&gt;"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "调用了__toString()方法\n"<span style="color: rgba(0, 0, 0, 1)">;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span> __set(<span style="color: rgba(128, 0, 128, 1)">$key</span>, <span style="color: rgba(128, 0, 128, 1)">$value</span><span style="color: rgba(0, 0, 0, 1)">){
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "&lt;hr&gt;"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "调用了__set()方法\n"<span style="color: rgba(0, 0, 0, 1)">;
      }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span> __get(<span style="color: rgba(128, 0, 128, 1)">$key</span><span style="color: rgba(0, 0, 0, 1)">) {
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "&lt;hr&gt;"<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">echo</span> "调用了__get()方法\n"<span style="color: rgba(0, 0, 0, 1)">;
      }
    }
   
    </span><span style="color: rgba(128, 0, 128, 1)">$ji</span> = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> animal();<br>  //初始化对象,调用__construct
    </span><span style="color: rgba(128, 0, 128, 1)">$ji</span>-&gt;name = 1<span style="color: rgba(0, 0, 0, 1)">;<br>  //对不可访问的属性赋值,调用__set
    </span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 128, 1)">$ji</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">name;<br>   //调用不可访问的属性,调用__get
    </span><span style="color: rgba(128, 0, 128, 1)">$ji</span>-&gt;<span style="color: rgba(0, 128, 128, 1)">sleep</span><span style="color: rgba(0, 0, 0, 1)">();<br>  //这里只是为了方便看出调用了sleep,使用serialize序列化之前会自动调用__sleep
    </span><span style="color: rgba(128, 0, 128, 1)">$ser_ji</span> = <span style="color: rgba(0, 128, 128, 1)">serialize</span>(<span style="color: rgba(128, 0, 128, 1)">$ji</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 128, 128, 1)">print_r</span>(<span style="color: rgba(128, 0, 128, 1)">$ser_ji</span><span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 128, 128, 1)">print_r</span>(<span style="color: rgba(0, 128, 128, 1)">unserialize</span>(<span style="color: rgba(128, 0, 128, 1)">$ser_ji</span><span style="color: rgba(0, 0, 0, 1)">))<br>  //在使用unserialize反序列化时调用__wakeup方法<br> <br>
</span>?&gt;</pre>
</div>
<p><strong>就会出现如下结果,调用两次__destruct方法是因为在animal类的一个对象被序列号后的字符串又被反序列化时调用</strong></p>
<p><strong>在程序结束时又会调用。</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/2357704/202107/2357704-20210709111015196-223222608.png" alt="" width="553" height="338" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="font-size: 18pt">序列化例子</span></p>
<div class="cnblogs_code">
<pre>&lt;?<span style="color: rgba(0, 0, 0, 1)">php
</span><span style="color: rgba(0, 0, 255, 1)">class</span> <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)">{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(128, 0, 128, 1)">$team</span> = 'Nolan123'<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(128, 0, 128, 1)">$team_name</span> = 'power'<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(128, 0, 128, 1)">$team_group</span> = 'biubiu'<span style="color: rgba(0, 0, 0, 1)">;

    </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> test(){
      </span><span style="color: rgba(128, 0, 128, 1)">$this</span>-&gt;<span style="color: rgba(128, 0, 128, 1)">$team_members</span> = 'hard work!'<span style="color: rgba(0, 0, 0, 1)">;
    }
}
</span><span style="color: rgba(128, 0, 128, 1)">$object</span> = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(0, 128, 128, 1)">serialize</span>(<span style="color: rgba(128, 0, 128, 1)">$object</span><span style="color: rgba(0, 0, 0, 1)">);
</span>?&gt;</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;<strong>运行结果</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/2357704/202107/2357704-20210709112617363-416912156.png" alt="" width="727" height="116" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;<strong>对象类型:对象长度:“对象名称”:类里面的变量个数:{变量类型:长度:“名称”;类型:长度:值;.......}</strong></p>
<p><strong>O是指一个对象,6是object的长度,3是有三个属性,{}里面是属性的内容; ss是team的类型,4是team长度,以此类推。</strong></p>
<p><strong>注意类里面的方法不会参加序列化。</strong></p>
<p><strong>需要注意的是变量受到不同修饰符(public,private,protected)修饰进行序列化时,序列化后变量的长度和名称会发生变化。</strong></p>
<ul>
<li><span style="color: rgba(255, 153, 0, 1)">使用public修饰进行序列化后,变量$team的长度为4,正常输出。</span></li>
<li><span style="color: rgba(255, 153, 0, 1)">使用private修饰进行序列化后,会在变量$team_name前面加上类的名称,在这里是object,并且长度会比正常大小多2个字节,也就是9+6+2=17。</span></li>
<li><span style="color: rgba(255, 153, 0, 1)">使用protected修饰进行序列化后,会在变量$team_group前面加上*,并且长度会比正常大小多3个字节,也就是10+3=13。</span></li>
</ul>
<p><strong>通过对比发现,在受保护的成员前都多了两个字节,受保护的成员在序列化时规则:</strong></p>
<p><strong>  1. 受Private修饰的私有成员,序列化时: \x00 + [私有成员所在类名] + \x00 [变量名]</strong></p>
<p><strong>  2. 受Protected修饰的成员,序列化时:\x00 + * + \x00 + [变量名]</strong></p>
<p><strong>  其中,"\x00"代表ASCII为0的值,即空字节," * " 必不可少。</strong></p>
<p><strong>序列化格式中字母的意思:</strong></p>
<div class="cnblogs_code">
<pre>a - <span style="color: rgba(0, 0, 255, 1)">array</span>                  b - <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">
d </span>- <span style="color: rgba(0, 0, 255, 1)">double</span>                   i - <span style="color: rgba(0, 0, 255, 1)">integer</span><span style="color: rgba(0, 0, 0, 1)">
o </span>- common <span style="color: rgba(0, 0, 255, 1)">object</span>            r -<span style="color: rgba(0, 0, 0, 1)"> reference
s </span>- <span style="color: rgba(0, 0, 255, 1)">string</span>                   C - custom <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)">
O </span>- <span style="color: rgba(0, 0, 255, 1)">class</span>                  N - <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">
R </span>- pointer reference      U - unicode <span style="color: rgba(0, 0, 255, 1)">string</span></pre>
</div>
<p><span style="font-size: 18pt">反序列化</span></p>
<p>使用序列化后的字符串,用反序列化函数unserialize进行反序列化</p>
<div class="cnblogs_code">
<pre>&lt;?<span style="color: rgba(0, 0, 0, 1)">php
</span><span style="color: rgba(0, 0, 255, 1)">class</span> <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)">{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(128, 0, 128, 1)">$team</span> = 'Nolan123'<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(128, 0, 128, 1)">$team_name</span> = 'power'<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">protected</span> <span style="color: rgba(128, 0, 128, 1)">$team_group</span> = 'biubiu'<span style="color: rgba(0, 0, 0, 1)">;

    </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> test(){
      </span><span style="color: rgba(0, 0, 255, 1)">echo</span> <span style="color: rgba(128, 0, 128, 1)">$this</span>-&gt;team." hard work!&lt;br&gt;"<span style="color: rgba(0, 0, 0, 1)">;
    }
}
</span><span style="color: rgba(128, 0, 128, 1)">$object</span> = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)">();
</span><span style="color: rgba(128, 0, 128, 1)">$ser</span> = <span style="color: rgba(0, 128, 128, 1)">serialize</span>(<span style="color: rgba(128, 0, 128, 1)">$object</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "<span style="color: rgba(128, 0, 128, 1)">$ser</span>&lt;br&gt;"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(128, 0, 128, 1)">$ser</span> = <span style="color: rgba(0, 128, 128, 1)">unserialize</span>(<span style="color: rgba(128, 0, 128, 1)">$ser</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(128, 0, 128, 1)">$ser</span>-&gt;<span style="color: rgba(0, 0, 0, 1)">test();
</span><span style="color: rgba(0, 128, 128, 1)">var_dump</span>(<span style="color: rgba(128, 0, 128, 1)">$ser</span><span style="color: rgba(0, 0, 0, 1)">);
</span>?&gt;</pre>
</div>
<p>调用test方法,用var_dump方法打印所有的对象,可以查看对象内部的数据结构</p>
<p><img src="https://img2020.cnblogs.com/blog/2357704/202107/2357704-20210709115542829-332450514.png" alt="" width="1074" height="148" loading="lazy"></p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/byErichas/p/14989539.html
頁: [1]
查看完整版本: PHP反序列化