Wadslog

[PHP] unserializeと__PHP_Incomplete_Class

Jan 22, 2008

昨日のZend_Feed::import() でフィードを取得した結果をキャッシュ化するとデータがおかしくなる件の続きです。 まず、Zend_Feed::import()で直接取得したフィードとキャッシュから取得したものそれぞれをvar_dump()で比較してみました。 Zend_Feed::import()の場合は、

object(Zend\_Feed\_Atom)#3 (8) {
    ...

キャッシュから取得した場合は、

object(\_\_PHP\_Incomplete\_Class)#3 (2) {
    ...

となっていました。 __PHP_Incomplete_Classについて調べたところ、オブジェクト型の変数をunserialize()を実行する場合には、事前に必要なクラスが定義されていないと正しく非シリアル化できないとありました。 当初の予想通りシリアライズ関連のところでおかしくなっていたようです。 前回のフィードの取得および、キャッシュ化のところを見ると、unserialize()を実行しているところは、前回の例では$cache->load()の中なので、たしかに必要なクラス(今回はZend_Feed_Atom)が定義されていませんでした。

$cache = Zend\_Cache::factory('Core', 'File', $frontendOptions, $backendOptions);
if(!$result = $cache->load('rss')) {
    try {
        $result = Zend\_Feed::import('http://wadslab.net/category/Zend\_Auth/atom/');
    } catch (Zend\_Feed\_Exception $e) {
        // フィードの読み込みに失敗しました
        echo "フィードの読み込み中に例外が発生: {$e->getMessage()}n";
        exit;
    }
    $cache->save($result);
}

対策としては、事前に必要なクラスを定義しておくほかに、unserialize_callback_func ディレクティブを利用する方法もあります。 unserialize_callback_func ディレクティブによって設定された コールバック関数は、unserializeする際に未定義のクラスをインスタ ンス化する度に呼び出されるので、この関数内で必要なクラスを定義することで__PHP_Incomplete_Classの発生を防ぐことが出来ます。 設定の方法は以下のとおりです。

// my\_callback\_funcは任意
ini\_set('unserialize\_callback\_func', 'my\_callback\_func');

function my\_callback\_func($classname)
{
   // $classname が必要なクラス名なので、これを定義します
}

クラス名=ファイル名.phpになっていれば以下のように定義すればいいです。

require\_once $classname.".php"

必要なクラスがZend Frameworkの場合には、

Zend\_Loader::loadClass($classname);

とすればいいでしょう。 というわけで、今回はZend Frameworkはまったく関係ありませんでした。

comments powered by Disqus