- ベストアンサー
Re: Cookieを使ってオブジェクトの引渡しはできるか?.
OKWebでは自己フォローができないみたいなので,改めます.QNo.63140,PHPカテゴリでの通しNo.32の質問の続きです.って言うか自己レス. 質問文中で大きな間違いをしているのがとても恥ずかしいので,訂正します. > setCookie( "cookie", serialize($obj), mktime("2010/8/1 00:00:00") ); mktime()ではなく,strtotime()です.何をやってるんだ俺は. それから,実験ですが,オブジェクトのunserialize()時に同名のクラスの定義があっても,そのクラスのインスタンスとしては取り扱ってくれませんでした. せっかくserialize()時にクラス名まで保存しているんだから,同名のクラス定義があったら読みに行ってくれたらいいのになぁ. という,ぼやき混じりの無意味な自己レスでした.以上.回答してくださった方(a-kumaさんだけ?),どうもありがとうございました.
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
>PHPLIBのserialize()は,確か特定のクラスのメソッドとして実装されていましたよね・・・.そのクラスの各サブクラスは,serialize()を各々オーバーロードしてたんでしょうか・・・ えーと、使い方はこのserializeを持つクラスを継承して使うわけではありません このserialize機能を持つクラスはセッション管理機能のクラスで ページの最初にpage_open(array("sess" => "session管理クラス名"); ページの最後にpage_close(); を呼び出すことによりその間で$sess->register("変数名");($sessはグローバルなオブジェクト、page_openのセッション管理クラスで指定されたクラスのインスタンス) としてやることによりpage_close()時にメンバ関数のregisterで登録したオブジェクトをserializeし、次にpage_open()されたときにunserializeされるようになってます。 よってserializeするオブジェクトにはセッションクラスを継承する必要はありません ただ、PHP3ではクラスの名前とメンバ変数の名前を取得することができないのでserializeされるクラスに$classnameと$persistent_slotsいうメンバ変数が必要です $classnameにはクラスの名前を、また、$persistent_slotsにメンバ変数の名前を配列として入力しなくてはなりません ex. class hogehoge { var $classname = "hogehoge"; var $foo; var $bar; var $baz; var $persistent_slots = array("foo", "bar", "baz"); /* 以下 メンバ関数の定義などが続く・・・ */ ... } PHP内では <? page_open("sess" => "session"); $fugafuga = new hogehoge; $sess->register("fugafuga"); ...適当にいろいろな処理... page_close(); ?> としてやれば、別ページでpage_open()された時点でオブジェクト$fugafugaが再生されます 使い方はこんなとこです 実際に中での動作は・・・というと $hogehogeをserializeしたいとする $sess->register("hogehoge");としておくと・・・ ここからserialize... global $hogehoge; // 実際には$hogehogeも変数に入った文字列なのでevalを用いなければいけない $serialize_opcode = "\$hogehoge = new $hogehoge->classname;"; while($variable = each($hogehoge->persistent_slots)) { $serialize_opcode .= "\$hogehoge->" . $variable . " = " . eval("\$hogehoge->$variable") . ";"; } としてやって何らかの方法でこの$serialize_opcodeを別のページに持っていってやり(PHPLIBではcookieまたはget methodでunique idを発行してそのidとDBのserial値を適合させることによりページ間移動を実現しています)、受け取ったページでeval($serialize_opcode);としてやれば$hogehogeが使える・・・というわけです ちなみに実際のserializeのコードはもっと複雑です。メンバ中に配列やクラスがある場合、再帰処理でどんどんもぐってserializeしなくてはいけませんので・・・ >serialize()がある程度各クラスに対してポータブルにかかれていたんでしょか?. 基本的にPHPには3つのデータ型しかありません スカラ型、配列、オブジェクトです スカラ型は変数名がわかれば値が取得できるため、永続化は容易です 配列も変数名がわかれば、eachで全メンバが取得できます。ハッシュも同様。 オブジェクトが問題で上記のようにクラス名、およびメンバ名の一覧がないと永続化が不可能です(言語仕様でサポートされれば別ですが・・・) よってこの3つを再帰的にたどることができればどのようなデータ型もserializeすることが可能です(実際には参照でループリング作ったら永久ループすると思いますが・・・) >そう言えば,クラス間キャストが出来ないとなると,いわゆる「多態性」ってやつはどうなるんですか?. あんまりPHPにそういうものを期待しないってのが一番の解決法です(^^; PHP4ではどうか知りませんがPHP3ではデストラクタすらありませんでした・・・ ちょっと忘却してしまいましたが、ほかにも結構変なところはありましたよ・・・ C++な感じで組んでると痛い目を見ることは確かです(^^;
その他の回答 (2)
- alfeim
- ベストアンサー率58% (114/195)
つい先日までPHPで仕事をしてました んと、serializeがあるって事は多分PHP4なのでしょうか? こちらはPHP3+i18nパッチ+PHPLIBでやってましたが PHPLIBの中に変数の永続化の機能があり、その中でclassのsirialize、unsirializeもしてましたよ やり方はserializeでクラスの内容を読みこみ再構築コードを文字列として作成し、unserialize時にそれをevalする、と言う手法を取っていました なので、クラス定義はunserialize前に自分で読んでおく必要がありました 元質問の方を見た限り、PHPLIBの手法でやれば解決できると思います とりあえずPHPLIBをダウンロードしてソースコードを眺めてみてはいかがでしょうか? 確か、session.incのserialize()がメンバ関数として定義してありますのでその辺を見てください PHPLIBの解説、マニュアルの日本語版、ダウンロード場所は参考URLを見てください
お礼
適切なアドバイス,ありがとうございます.ただ,私の場合処理系ハックは本業ではないので,機仮名にやってみようと思います.
補足
> その中でclassのsirialize、unsirializeもしてましたよ > やり方はserializeでクラスの内容を読みこみ > 再構築コードを文字列として作成し、unserialize時に > それをevalする、と言う手法を取っていました なるほど.とりあえずphpの標準ライブラリの仕様はそんなに読み込んでいないので,具体的にどういうコードになっているのかちょっと想像がつきませんが,「読めば多少は理解」出来そうな感じ(ほんとか?)ですね. それでは,読ませていただきます. 「ひとりごと」. PHPLIBのserialize()は,確か特定のクラスのメソッドとして実装されていましたよね・・・.そのクラスの各サブクラスは,serialize()を各々オーバーロードしてたんでしょうか・・・,それとも,元のserialize()がある程度各クラスに対してポータブルにかかれていたんでしょか?. そう言えば,クラス間キャストが出来ないとなると,いわゆる「多態性」ってやつはどうなるんですか?.
- a-kuma
- ベストアンサー率50% (1122/2211)
> mktime()ではなく,strtotime()です.何をやってるんだ俺は よくあることです :-) CGIのデバッグ中に、cookieが保存されてなくて、うんうんうなって 三日くらいたってから localhost だと cookie が保存されないと いうことを知って昇天した奴を知ってます >俺だ (^^; PHPも、そこここで見かけるようになりましたので、きちんと オブジェクトのシリアライズができる(*)ようになるのは、そんなに 遠いことではない、と期待してます。 (*) オブジェクトのシリアライズで、クラスを復元しない というのは、ちょっと納得できんですが perl でも、(見かけ上)オブジェクトを扱えるので、PHPも オブジェクト(らしいもの)を扱えない、というわけにはゆかず、 おまけ程度でもつけた、という感じですものね。 あの後、ちょっと思いついたのですが、それなりに需要のある クラスなのであれば、unserialize()+属性のコピーを受け持つ Factory クラスを実装しておく、というのが良いのかなあ、 と思ってます。 もう一つは、クラスも復元をするように stanaka さんが patch をあてて、本家に取り込んでもらうという手も :-) # ぼやきに共感する a-kuma でした
補足
> よくあることです :-) > CGIのデバッグ中に、cookieが保存されてなくて、うんうんうなって > 三日くらいたってから localhost だと cookie が保存されないと > いうことを知って昇天した奴を知ってます >俺だ (^^; これとは違いますが,phpをはじめて触ると,1ファイルが1ページと同期して動く,ということが理解しにくい場合があります.私は,頭のほうでsetCookie()とかやっといて,ページをもう一度読みなおさずに必死でCookie変数を探していたことがありました.(そんなバカな!!) > perl でも、(見かけ上)オブジェクトを扱えるので、PHPも > オブジェクト(らしいもの)を扱えない、というわけにはゆかず、 > おまけ程度でもつけた、という感じですものね。 そうなんですか,残念ですねぇ. > もう一つは、クラスも復元をするように stanaka さんが patch > をあてて、本家に取り込んでもらうという手も :-) ははぁ,そう来ますか(笑).当方,まだ処理系のソースをハックするほど手馴れたプログラマではないんですが,勉強がてら,ひまを見つけてやってみることにしましょうかねぇ.それともphp自身で実装できそうですか?.
補足
まず,非常にご丁寧なご返事に感謝します.ここまで教えていただけるとは思っていませんでした.いまさらこんなことを言ってしまうとご気分を害されるかもしれませんが,質問内容が途中から(アルバイトの)仕事とは関係のない,興味本位のものになっていました.申し訳ありません.ひょっとして気づいておられたかもしれませんが,それでも付き合っていただいたことに,お礼を申し上げます. ご返事をいただいてから「しまった!」と思ったのですが,本来避けるべき手取り足取りのご返事をいただくような質問をして,少し反省をしております. > ページの最初にpage_open(array("sess" => "session管理クラス名"); > ページの最後にpage_close(); > を呼び出すことによりその間で$sess->register("変数名");($sessはグローバルなオブジェクト、> page_openのセッション管理クラスで指定されたクラスのインスタンス) > としてやることによりpage_close()時にメンバ関数のregisterで登録したオブジェクトを > serializeし、次にpage_open()されたときにunserializeされるようになってます。 ここのところの概念がよくわかっていなかったので,妙な質問をしました.Sessionクラスのインスタンスは自分以外の変数,オブジェクトのserialize(),unserialize()を行うために,各ページごとに生成されるオブジェクトだったのですね. > $classnameにはクラスの名前を、また、$persistent_slotsにメンバ変数の名前を配列として > 入力しなくてはなりません a-kumaさんからメンバ変数の復活(unserialize()された「擬似」オブジェクトからのコピー)のためのメソッド,というアドバイスを頂いたとき,これと同じようなことを僕も考えました.しかし,serialize()を施したいクラスそれぞれに関していちいちそのほう名メンバを定義するのも,スマートじゃない気がしますし,こういう機能はむしろ,ユーザ側のライブラリではなく,言語処理系の側で実装する昨日のように思われます. それにPHP4のserialize()に一応,クラス名というシンボルが残されている以上,こちらを使ったほうがいいのでは,と今は思っています.ただし,ご指摘を受けるまでオブジェクト型のメンバ変数の参照先,というところまでは考えが及びませんでしたが・・・(どうしよう). > オブジェクトが問題で上記のようにクラス名、およびメンバ名の一覧がないと永続化が不可能です > (言語仕様でサポートされれば別ですが・・・) まさしく. それから・・・. > そう言えば,クラス間キャストが出来ないとなると,いわゆる「多態性」って > やつはどうなるんですか?. 自分で書いといて何ですが,この質問は無意味だったと思います.多重継承やインターフェースのような実装されていない機能についてはともかく,PHP4のオブジェクトへの参照型変数は,おっしゃるようにそれ以上の「型」なんてありませんから,相手がどんなクラスであろうと与えられたシンボルのメソッドを探しに行くんですよねぇ. if( condition_A ){ $obj = new ClassA(); }else if( condition_B ){ $obj = new ClassBNoRelationshipWithClassA(); // ClassAとは全く継承関係のないClassB }else{ $obj = new ClassCExtendsClassA(); // ClassAのサブクラスClassC } $result = $obj->method_name(); // 各クラスにmethod_name()がありさえすれば // エラーは出ない あたりまえのことでした.これが型チェックがないことの副作用か,ポリモーフィズムへの指向かは知りませんが.(ひょっとして僕は「多態性」を誤解してますでしょうか?) いずれにせよ,今回の質問ではいちいち丁寧なご回答をいただき,本当に感謝しております.ありがとうございました.