Zend_Session_Namespaceの便利だけど厄介なところ〜保存方法は$session->hoge=XXXだけじゃない〜

今さらマサラタウンなZend Frameworkの話。 昔のサービスとかだと今でも健在なのか知らないけどどうなんだろう。とりあえず最近触る機会があったのでその時に詰まったことを書いていく。

今回書くのはZendのセッション管理をするクラス、Zend_Session_Namespaceの話。

Zend_Session_Namespaceでクラスオブジェクトを保存するときは気をつけて

class Hoge {
    protected $name;

    public function setProperty() {
        $this->name = 'TANAKA';
    }
}

$session = new Zend_Session_Namespace('hoge')
$session->hoge = new Hoge();

この時、$session->hoge->setProperty();としてやればクラスHogeのメソッドであるsetProperty()が実行できる。 実行すると$session->hogeの$nameに'TANAKA'がセットされる。 この状態で

echo $session->hoge->name;

とすれば'TANAKA'と表示されるだろう。ここまでは想定通りの動きである。 しかし、Zend_Session_Namespaceをなめてはいけない、内部的にはさらにもう一つ処理をしている。

なんとセッションファイルのhogeにもセットした値を書き込んでいる(更新している)のだ

セッションの保存ファイルの中身

Zend_Session_Namespaceで保存されるセッションファイルの動きを見てみよう。(デフォルトだと/tmpにsess_cabaXXXXのように保存されている)

まずは普通にセッションに保存してみる。

$session = new Zend_Session_Namespace('hoge')
$session->hoge = new Hoge();

セッションファイルは以下のような感じ。

▶cat /tmp/sess_cabeaa46f389c04badfb94d7712681b4
hoge|a:1:{s:4:"hoge";O:4:"Hoge":1:{s:7:"*name";N;}}

そして$session->hoge->setProperty();を実行してみよう。以下のようにセッションファイルが更新されているはずだ。

▶cat /tmp/sess_cabeaa46f389c04badfb94d7712681b4
hoge|a:1:{s:4:"hoge";O:4:"Hoge":1:{s:7:"*name";s:6:"TANAKA";}

見事に更新したプロパティの値が入っている。 便利、、、といえば便利だが割と初見殺しではある。

例えばセッションの管理をファイルではなくDBに保存するように修正する場合、セッションを保存している箇所を探すだろう。 その際、保存するのは$session->hoge = XXX; のように「=」で入れている箇所だけ見ているとアウトだ。 Zend_Session_Namespaceではセッションにインスタンスを保存していた場合、実行されたメソッドも見る必要がある。

なんでこういう仕組みになっているのか

結構じっくり調べてみたら、インスタンスのメンバ変数が変わったときにセッションファイルも更新されるのはZend_Session_Namespaceの機能ではなかった。(今まで書いたことは忘れてくださいごめんなさい)

そもそもの$_SESSIONで更新機能は存在していた。Zend_Session_Namespaceを使わず$_SESSIONを使って再現してみる。

$_SESSION['hoge'] = new Hoge();
$_SESSION['hoge']->setProperty();

これでも以下のようにセッションファイルは更新される。

▶cat /tmp/sess_cabeaa46f389c04badfb94d7712681b4
hoge|a:1:{s:4:"hoge";O:4:"Hoge":1:{s:7:"*name";s:6:"TANAKA";}

最初はZend_Session_Namespaceに実装されているマジックメソッド__set__getが関連しているのかと思ったが違った。 $_SESSIONの内部的な動きはつかめていないが、おそらくメンバ変数にアクセスするたびにファイル書き込みの処理が挟み込まれているのかなと推測する。そのあたりの仕組みってどうやって調べたらいいんだろ、phpのソース見るしかないのかな、、、