【PHP】シリアライズとマジックメソッド

シリアライズとマジックメソッドの使用方法について自分なりにまとめてみました。

## シリアライズとは？
[公式ドキュメント](https://www.php.net/manual/ja/function.serialize.php)によると
> 値の保存可能な表現を生成します。
型や構造を失わずに PHP の値を保存または渡す際に有用です。

と記載されています。

シリアライズは、配列やオブジェクトを文字列に変換することができます。
そうすることで型を保ったままDBに保存することが可能になります。

## シリアライズの使い方
`serialize()`を使用することでシリアライズ化ができます。

```php
<?php

$hoge = array(1, 2, 3);
$fuga = serialize($hoge);
var_dump($fuga);

// 結果
string(30) "a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}"
```

戻す際は、`unserialize()`を使用することで、元の型へ復元できます。

```php
<?php
$hoge = array(1, 2, 3);
$fuga = serialize($hoge);
$piyo = unserialize($fuga);
var_dump($piyo);

// 結果
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}
```

## オブジェクトのシリアライズ
次にオブジェクトのシリアライズについて確認していきます。
先ほどと同じようにシリアライズ化していきます。

```php
class Hoge {
    protected $fuga;
    private $piyo;
    public function __construct() {
        $this->fuga = 1;
        $this->piyo = 2;
    }
}

$object = new Hoge();
$serialize_object = serialize($object);
var_dump($serialize_object);

// 結果
string(55) "O:4:"Hoge":2:{s:7:"*fuga";i:1;s:10:"Hogepiyo";i:2;}"
```

シリアライズに成功しました。
結果に記載されている通り、オブジェクトをシリアライズ化するとプロパティ名のみが保持されます。
`protected`なプロパティには`*`が`private`なプロパティにはクラス名が付きます。

このまま、`unserialize()`してみます。

```php
<?php
class Hoge {
    protected $fuga;

    private $piyo;
    
    public function __construct() {
        $this->fuga = 1;
        $this->piyo = 2;
    }
}

$object = new Hoge();

$serialize_object = serialize($object);
$unserialize_object = unserialize($serialize_object);
var_dump($unserialize_object);

// 結果
object(Hoge)#2 (2) {
  ["fuga":protected]=>
  int(1)
  ["piyo":"Hoge":private]=>
  int(2)
}
```
しっかりとオブジェクトの型を保ったまま復元できました。

## __sleep()とは？
次に`__sleep()`について見ていきます。
`__sleep()`はオブジェクトをシリアライズする際にクラスに定義されていれば実行されるマジックメソッドです。
定義していない場合は、先程の例と同じようにプロパティの値がシリアライズされます。
`__sleep()`はシリアライズする必要のないプロパティを取り除くときに使います。
プロパティに設定されていない変数名をしているとエラーとなります。

```php
<?php
class Hoge {
    protected $fuga;
    private $piyo;
    
    public function __construct() {
        $this->fuga = 1;
        $this->piyo = 2;
    }
    
    public function __sleep() {
        return ['fuga'];
    }
}

$object = new Hoge();
$serialize_object = serialize($object);
var_dump($serialize_object);

// 結果
string(33) "O:4:"Hoge":1:{s:7:"*fuga";i:1;}"
```

##__wakeup()とは？
次に`__wakeup()`について見ていきます。
`__wakeup()`は、`__sleep()`の逆です。
シリアライズから戻す際に、定義されていれば実行されるマジックメソッドです。

```php
<?php
class Hoge {
    protected $fuga;

    private $piyo;
    
    public function __construct() {
        $this->fuga = 1;
        $this->piyo = 2;
    }
    
    public function __sleep() {
        return ['fuga'];
    }
    
    public function __wakeup() {
        $this->fuga = 3;
        $this->piyo = 4;
    }
}

$object = new Hoge();
$serialize_object = serialize($object);
$unserialize_object = unserialize($serialize_object);
var_dump($unserialize_object);

// 結果
object(Hoge)#2 (2) {
  ["fuga":protected]=>
  int(3)
  ["piyo":"Hoge":private]=>
  int(4)
}
```

## シリアライズをする際の注意点
①保存時の注意点
[公式ドキュメント](https://www.php.net/manual/ja/function.serialize.php)にある通り
> これはバイナリ文字列であり、null バイトを含む可能性もあることに注意しましょう。 保存したり利用したりするときも、null バイトが含まれることを想定しておかないといけません。 たとえば、serialize() の出力をデータベースに格納するときには、 通常は CHAR 型や TEXT 型ではなく BLOB 型を使わないといけません。

シリアライズ結果を保存する際は、BLOB型を使用してください。

②親クラスのprivate
`__sleep()`を使用する際に、親クラスのprivateなプロパティは処理することができません。

以上参考になれば幸いです！