0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PHPでSimpleXMLElementを持ったオブジェクトをキャッシュしたい時

Last updated at Posted at 2018-10-23

結論:__sleep()と__wakeup()を使う

以下のようなSimpleXMLElementをプロパティとして持ったクラスのオブジェクトを、Serializeしてキャッシュしたい場合があります。

MyClass.php
<?php
namespace App;
use SimpleXMLElement;

class MyClass
{
    /**
     * @var SimpleXMLElement
     */
    public $xml;

    /**
     * @param  SimpleXMLElement  $xml
     * @return void
     */
    public function __construct(SimpleXMLElement $xml)
    {
        $this->xml = $xml;
    }
}

例えばこのクラスのオブジェクトをLaravelでそのままキャッシュしようとすると、「SimpleXMLElementをシリアライズできないよ」というエラーで怒られます。

解決策としてPHPのマジックメソッドである__sleep()と__wakeup()を使用します。
先ほどのMyClassに以下のメソッドを追記。

    public function __sleep()
    {
        $this->xml = $this->xml->asXml();

        return ['xml'];
    }

    public function __wakeup()
    {
        $this->xml = simplexml_load_string($this->xml);
    }

シリアライズされる前に__sleep()が呼ばれ、その中ではSimpleXMLElementをXML文字列に変換しています。
そしてアンシリアライズされる時に__wakeup()の中で再度SimpleXMLElementに変換するような形。

参考:PHP: マジックメソッド - Manual
http://php.net/manual/ja/language.oop5.magic.php

Laravelの時の注意点

Laravelではrememberというキャッシュがなければオリジンを取得し、そして保存して返すというメソッドがあります。
保存して返すというところがミソですが、これは以下のような問題を引き起こします。

  1. MyClassをキャッシュへ保存しようとする
  2. 保存する際に__sleep()メソッドによりxmlプロパティがstringへ変換される
  3. xmlプロパティがstringであるオブジェクトがrememberメソッドより返される

このように、初回(オリジンを取得する際)に__wakeup()が呼ばれないという事態に陥ってしまいます。
これは以下のように対処します。

$item= Cache::remember('item', 30, function () {
    return new MyClass($someSimpleXMLElement);
});

if (is_string($item->xml)) {
   $item->__wakeup();
}

return $item;
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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?