LoginSignup
0
0

More than 3 years have passed since last update.

jsson_encodeとserializeでハマった話

Posted at

はじめに

サイト共通の重い計算処理を各ページでやるコストが高いので、処理結果をobj化してDBに保存して使いまわしたい
・・・と考えた。

最初にやってみた方法

保存用テーブル

CREATE TABLE IF NOT EXISTS `xxxx_save_t` (
  `xxxx_save_id` int(11) NOT NULL AUTO_INCREMENT,
  `data` longblob NOT NULL,
  `create_time` datetime NOT NULL,
  `update_time` datetime NOT NULL,
  `delete_time` datetime DEFAULT NULL,
  `delete_flg` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`xxxx_save_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

保存処理

 $obj = xxxx //何某かの処理が終わった状態結果を持つインスタンス
 db::save(json_encode($obj));

読み込み処理

  $data = db::SelectById($id);
  $obj = json_decode($data['data']);

なぜか一部のデータが消える!

  • $objが持つはずのプロパティが消える・・・

原因

json_encodeでオブジェクトを保存する場合、対象はpublicプロパティのみ
インスタンスのprivate/protect変数も状態として保存したい場合には向かない。
あとは配列とオブジェクトが混ざってるような場合もserializeの方が良さそうか。
【PHP】オブジェクトをjsonエンコード

再現

    class CustomDateTime {
        public $_dateTime = null;
        protected $_dateStr     = "";
        protected $_isSet       = false;

        public function __construct($date) {
            $this->_dateTime = new DateTime($date);
            $this->_dateStr = $date;
            $this->_isSet = true;
        }
    }

    public function test() {

        $tmpData = [
            'array'         => [1,2,3],
            'customDateTime'    => new CustomDateTime('2020-1-1'),
        ];
        var_dump($tmpData);
        var_dump("<br/><br/>");

        $tmpData2 = json_decode(json_encode($tmpData));
        var_dump($tmpData2);exit;
    }

結果

array(2) { ["array"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["customDateTime"]=> object(CustomDateTime)#43 (3) { ["_dateTime"]=> object(DateTime)#44 (3) { ["date"]=> string(19) "2020-01-01 00:00:00" ["timezone_type"]=> int(3) ["timezone"]=> string(10) "Asia/Tokyo" } ["_dateStr":protected]=> string(8) "2020-1-1" ["_isSet":protected]=> bool(true) } } string(10) "

object(stdClass)#45 (2) { ["array"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["customDateTime"]=> object(stdClass)#46 (1) { ["_dateTime"]=> object(stdClass)#47 (3) { ["date"]=> string(19) "2020-01-01 00:00:00" ["timezone_type"]=> int(3) ["timezone"]=> string(10) "Asia/Tokyo" } } }

jsonを介した時点で非publicなdateStr/isSetが抹消された

対策

配列やオブジェクトのpublic変数だけでよければjson_encodeでよいがprotectの状態なども持たせたい場合はserializeを使う
Serialize PHP:Manual

Serializeを使ってみる

    public function test() {

        $tmpData = [
            'array'         => [1,2,3],
            'customDateTime'    => new CustomDateTime('2020-1-1'),
        ];
        var_dump($tmpData);
        var_dump("<br/><br/>");

        $tmpData2 = unserialize(serialize($tmpData));
        var_dump($tmpData2);exit;
    }

結果

array(2) { ["array"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["customDateTime"]=> object(CustomDateTime)#43 (3) { ["_dateTime"]=> object(DateTime)#44 (3) { ["date"]=> string(19) "2020-01-01 00:00:00" ["timezone_type"]=> int(3) ["timezone"]=> string(10) "Asia/Tokyo" } ["_dateStr":protected]=> string(8) "2020-1-1" ["_isSet":protected]=> bool(true) } }

array(2) { ["array"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } ["customDateTime"]=> object(CustomDateTime)#45 (3) { ["_dateTime"]=> object(DateTime)#46 (3) { ["date"]=> string(19) "2020-01-01 00:00:00" ["timezone_type"]=> int(3) ["timezone"]=> string(10) "Asia/Tokyo" } ["_dateStr":protected]=> string(8) "2020-1-1" ["_isSet":protected]=> bool(true) } }

非publicな状態も含めて変換された。

その他メモ

serializeは環境によっては文字関連でエラーになったりするそう
serialize VS json_encode 〜人類の存亡とか仁義とか全く関係ない戦い〜

保存サイズはjson_encodeの方が小さい。そりゃね。

まとめ

  • 配列で使うならさして違いは無い
  • オブジェクトを利用する場合スコープの影響が発生してくる
  • 純粋なデータの保存用途だけあればjson_encodeを使った方がコンパクト
  • 中身まで同じオブジェクトを再現したいのであればserializeがよさげ
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0