關於 PHP 序列化和反序列化不得不知道的細節

h6play發表於2020-03-09

在開發
例如:下載中心匯出的任務需要將處理類序列化到資料庫,或者Redis
例如:佇列任務需要將處理類序列化到 Redis 等
像如此常見的序列化操作,有很大機率出錯是很正常的

我們定義兩個類來測試

class A {
    protected $class;

    public function __construct($class) {
        $this->class = $class;
    }

    public function dd() {
        $this->class->d();
    }
}
class B {

    protected $x;
    protected $y;

    public function __construct($x, $y) {
        $this->x = $x;
        $this->y = $y;
    }

    public function d() {
        echo "Hello";
    }
}

我們需要這樣子輸出

  • 如果是直接傳入 類屬性 並且直接執行,那麼是能夠正常輸出的
    $b = new B(1,2);
    $a = new A($b);
    $a->dd();

如果我們序列化呢?

  • 先在程式中序列化
    $a = serialize($a);
  • 然後序列化得到字串
    O:1:"A":1:{s:8:" * class";O:1:"B":2:{s:4:" * x";i:1;s:4:" * y";i:2;}}
  • 然後我們在另外一個程式進行反序列化並且執行 $a->dd()
    $a = '<上面的序列化後的字串,輸入會導致格式顯示問題,所以我就不輸入了>';
    $a = unserialize($a);
    $a->dd();
  • 對的,你沒看錯,報錯了,居然報錯了!!!
    PS D:\data\文件> php a.php
    Fatal error: Uncaught Error: Call to a member function d() on null in D:\data\文件\a.php:11
    Stack trace:
    #0 D:\data\文件\a.php(31): A->dd()
    #1 {main}
    thrown in D:\data\文件\a.php on line 11

    結論

  • 在使用序列化的函式,允許對 類的繼承 進行序列化 (大家可以去測試一下,是正常的)
  • 在使用序列化的函式,允許對 基本屬性 進行序列化
  • 在使用序列化的函式,不允許 將別的類 傳入到 類屬性中 進行序列化
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章