• ベストアンサー

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さんだけ?),どうもありがとうございました.

  • PHP
  • 回答数3
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
  • alfeim
  • ベストアンサー率58% (114/195)
回答No.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++な感じで組んでると痛い目を見ることは確かです(^^;

stanaka
質問者

補足

 まず,非常にご丁寧なご返事に感謝します.ここまで教えていただけるとは思っていませんでした.いまさらこんなことを言ってしまうとご気分を害されるかもしれませんが,質問内容が途中から(アルバイトの)仕事とは関係のない,興味本位のものになっていました.申し訳ありません.ひょっとして気づいておられたかもしれませんが,それでも付き合っていただいたことに,お礼を申し上げます.  ご返事をいただいてから「しまった!」と思ったのですが,本来避けるべき手取り足取りのご返事をいただくような質問をして,少し反省をしております. > ページの最初に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()がありさえすれば // エラーは出ない  あたりまえのことでした.これが型チェックがないことの副作用か,ポリモーフィズムへの指向かは知りませんが.(ひょっとして僕は「多態性」を誤解してますでしょうか?)  いずれにせよ,今回の質問ではいちいち丁寧なご回答をいただき,本当に感謝しております.ありがとうございました.

その他の回答 (2)

  • alfeim
  • ベストアンサー率58% (114/195)
回答No.2

つい先日までPHPで仕事をしてました んと、serializeがあるって事は多分PHP4なのでしょうか? こちらはPHP3+i18nパッチ+PHPLIBでやってましたが PHPLIBの中に変数の永続化の機能があり、その中でclassのsirialize、unsirializeもしてましたよ やり方はserializeでクラスの内容を読みこみ再構築コードを文字列として作成し、unserialize時にそれをevalする、と言う手法を取っていました なので、クラス定義はunserialize前に自分で読んでおく必要がありました 元質問の方を見た限り、PHPLIBの手法でやれば解決できると思います とりあえずPHPLIBをダウンロードしてソースコードを眺めてみてはいかがでしょうか? 確か、session.incのserialize()がメンバ関数として定義してありますのでその辺を見てください PHPLIBの解説、マニュアルの日本語版、ダウンロード場所は参考URLを見てください

参考URL:
http://www.php.gr.jp/php/phplib/
stanaka
質問者

お礼

 適切なアドバイス,ありがとうございます.ただ,私の場合処理系ハックは本業ではないので,機仮名にやってみようと思います.

stanaka
質問者

補足

> その中でclassのsirialize、unsirializeもしてましたよ > やり方はserializeでクラスの内容を読みこみ > 再構築コードを文字列として作成し、unserialize時に > それをevalする、と言う手法を取っていました  なるほど.とりあえずphpの標準ライブラリの仕様はそんなに読み込んでいないので,具体的にどういうコードになっているのかちょっと想像がつきませんが,「読めば多少は理解」出来そうな感じ(ほんとか?)ですね.  それでは,読ませていただきます.  「ひとりごと」.  PHPLIBのserialize()は,確か特定のクラスのメソッドとして実装されていましたよね・・・.そのクラスの各サブクラスは,serialize()を各々オーバーロードしてたんでしょうか・・・,それとも,元のserialize()がある程度各クラスに対してポータブルにかかれていたんでしょか?.  そう言えば,クラス間キャストが出来ないとなると,いわゆる「多態性」ってやつはどうなるんですか?.

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.1

> mktime()ではなく,strtotime()です.何をやってるんだ俺は よくあることです :-) CGIのデバッグ中に、cookieが保存されてなくて、うんうんうなって 三日くらいたってから localhost だと cookie が保存されないと いうことを知って昇天した奴を知ってます >俺だ (^^; PHPも、そこここで見かけるようになりましたので、きちんと オブジェクトのシリアライズができる(*)ようになるのは、そんなに 遠いことではない、と期待してます。   (*) オブジェクトのシリアライズで、クラスを復元しない     というのは、ちょっと納得できんですが perl でも、(見かけ上)オブジェクトを扱えるので、PHPも オブジェクト(らしいもの)を扱えない、というわけにはゆかず、 おまけ程度でもつけた、という感じですものね。 あの後、ちょっと思いついたのですが、それなりに需要のある クラスなのであれば、unserialize()+属性のコピーを受け持つ Factory クラスを実装しておく、というのが良いのかなあ、 と思ってます。 もう一つは、クラスも復元をするように stanaka さんが patch をあてて、本家に取り込んでもらうという手も :-) # ぼやきに共感する a-kuma でした

stanaka
質問者

補足

> よくあることです :-) > CGIのデバッグ中に、cookieが保存されてなくて、うんうんうなって > 三日くらいたってから localhost だと cookie が保存されないと > いうことを知って昇天した奴を知ってます >俺だ (^^;  これとは違いますが,phpをはじめて触ると,1ファイルが1ページと同期して動く,ということが理解しにくい場合があります.私は,頭のほうでsetCookie()とかやっといて,ページをもう一度読みなおさずに必死でCookie変数を探していたことがありました.(そんなバカな!!) > perl でも、(見かけ上)オブジェクトを扱えるので、PHPも > オブジェクト(らしいもの)を扱えない、というわけにはゆかず、 > おまけ程度でもつけた、という感じですものね。  そうなんですか,残念ですねぇ. > もう一つは、クラスも復元をするように stanaka さんが patch > をあてて、本家に取り込んでもらうという手も :-)  ははぁ,そう来ますか(笑).当方,まだ処理系のソースをハックするほど手馴れたプログラマではないんですが,勉強がてら,ひまを見つけてやってみることにしましょうかねぇ.それともphp自身で実装できそうですか?.

関連するQ&A

  • Cookieを使ってオブジェクトの引渡しはできるか?.

     phpを勉強中の一アルバイトプログラマです.いろいろ弄くってみてよくわからないところがあるのですが,ひとつ質問させていただきたいと思います.  あるページから,別のページへオブジェクトを引き渡したいと思いました.一度ブラウザを終了しても引き続いて扱えるようにしたいと思っていたので,cookieを使って次のようにすることにしました. a.php: $obj = new ClassA(); setCookie( "cookie", serialize($obj), mktime("2010/8/1 00:00:00") );  マニュアルによるとserializeしたオブジェクトはプロパティの値しか保存されない,ということですので,勝手に推測して, b.php: $obj = (ClassA)unserialize($cookie);  としたところ,b.phpでparse errorが起こります.どうやらphpではクラス間のキャストができなさそうだ,というのはわかりますが,そうすると,処理の流れの中で一貫してひとつのオブジェクトを扱いたい場合,どのようにすればよいのでしょうか?.  ・・・家に帰ってきてから気が付いたのですが,オブジェクトをserializeしたstringには,クラス名の情報が含まれているようです.ということは,ひょっとしてクラス定義さえきっちりしておけばunserializeしたオブジェクトもきちんとクラスのインスタンスとしてあつかえるのか?.

    • ベストアンサー
    • PHP
  • Python3でのメタプログラミングについて

    下記の Ruby スクリプトと同じことを Python で行う場合、どのように実装すればいいでしょうか? <前提> ・メソッドを Klass クラスに実行時に動的に追加する。 ・追加したメソッドの動的削除、変更は必要ない。 ・メソッド定義は、Python のオブジェクトではなく単なる文字列。 ・メソッド内部から Klass クラス内のインスタンス変数にアクセスする。 ・Klass クラスや Klass インスタンスを扱う処理から、動的に追加したメソッドを呼び出す。 ・追加したメソッドはシングルトンメソッドである必要はない。 <目的> Klass クラスのカスタマイズ機能をメソッド定義文として外部に保存しておいて、実行時に呼び出して機能を拡張するような目的です。Klass クラスはめったに変更されないもの、カスタマイズ機能(メソッド定義文)はよく変更されるもの、という切り分けをしたいため、単純に多重継承や MixIn はしたくないです。(上手い方法があればいいのですが…) #!/usr/bin/env ruby # coding: utf-8 # 文字列のメソッド定義 $user_funcs = [' def user_foo() puts "foo" * @x end ', ' def user_bar() puts "bar" * @x end '] # ↑本来は文字列として外部DBに記録されている。 # ---- # # 拡張したいクラス # class Klass # インスタンス変数を持つ def initialize @x = 3 end attr_accessor :x # 文字列で定義されたメソッドを追加 $user_funcs.each do |f| eval f end end # ---- # # 呼出方法 # obj = Klass.new # 追加されたメソッド(user_から始まる名前)を列挙しながら実行する # => どんな定義がされていても、命名規則さえ守っていれば呼び出し側はそのメソッド名を知る必要はない。 obj.methods.select {|m| /^user_/ =~ m }.each do |m| eval "obj.#{m}" end # 追加されたメソッドはシングルトンメソッドではなく、あくまでもインスタンスメソッドである。 obj2 = Klass.new # インスタンス変数の書き換え obj2.x = 4 # インスタンスメソッドの書き換え def obj2.user_bar() puts "hoge" * @x end obj2.methods.select {|m| /^user_/ =~ m }.each do |m| eval "obj2.#{m}" end

  • クラス構造と継承のありかた?

    PHP初心者で勉強中の者です。 多少、長文気味ですがアドバイス頂けると幸いです。 環境は、レンタルサーバで、php ver 5.2、MySQL ver 5.0、ブラウザ IE8(最新ver) 質問1 : index.php上で以下の処理を毎回(webにアクセスするたび)行っています。    1.require_once で各phpファイルを読み込み(全てクラスファイル)    2.new で読み込んだクラスをインスタンス化    3.自作関数を実行(動的なhtmlを出力)   この様な繰り返し処理は、webプログラミングとして典型的なのでしょうか。   webによっては機能(メールやプロフィール)毎にindex.phpを設けているとも聞いています。 質問2 : 質問1の2や3で必要なクラスオブジェクトを引数として渡している現状ですが、これを効率化(引数の省略)させようと、セッション(serialize、unserialize)へと移行中です。勉強不足であり今ひとつ実装出来ていませんが、共通変数を設けて使い回す構造(最上位クラスのpublic変数に格納?)とどちらが現実的でしょうか。 以上、お願いします。

    • 締切済み
    • PHP
  • javascriptのコードについて

    以下のコードなのですが、 エンクロージャー関数の ローカル変数hogeをさらに、エンクロージャー内部で定義された 関数ででクロージャーとして保持させたいメソッドのコードですが var Method = function (){ var hoge = "初期値"; var getter = function (){ return hoge; } var setter = function (param){ hoge = param; return hoge; } return {"set" : setter,"get" : getter} } var obj = Method(); console.log(obj); console.log(obj . get()); obj.set("初期値変更"); console.log(obj.get()); obj . set("更に変更"); console.log(obj.get()); この場合、メソッドの返り値として、一般的な文献に乗っている関数(関数オブジェクト)を返すのではなく オブジェクトリテラルとして返しています。 この場合でも、動きとしてはクロージャーの動きをしているのでhogeという変数の保持はできているっぽいんですが クロージャーって関数内で定義された関数であれば、どういう返り値の返し方でも クロージャーになるのですかね? また、この方法は、一般的にjsで関数コンストラクタ呼び出しをしてインスタンスを作る際privateメンバを実現する方法として紹介されていますが、 これはクロージャーとして生成するたんびに内部の変数を保持するためメモリ食い虫になるらしいのですが まず間違いなく、このクラス(便宜上そう呼びます)のインスタンスはひとつしかつくることはない!!という仕様だとしても いけないのでしょうか? というかもう現状javascripのバッドノウハウ的なものになっているのでしょうか?

  • 外部ファイルのクラスのインスタンスが生成できない

    いつもお世話になっております。 PHP(Ver5.2)が利用できるレンタルサーバーを借りていろいろやっているのですが、 include_once した外部PHPファイルの中のクラス定義のコンストラクタがCallされません。 //外部クラスの記述 class A{ public function __construct(){ echo "OK"; } } //メインPHPの記述 include_once "xxx.php"; $obj = new A(); ↑におけるメインPHPをブラウザから呼び出したとき、本来なら OK とechoされるはずなのに、何も表示されません。 また、クラスAに定義したpublicなfunctionをCallしようとすると、定義されてないメソッドをCallした、とエラーになります。(インスタンス自体が生成されていない??) ファイル自体は正常にIncludeされていると思います。(ファイル名を間違ったらエラーになったから) ちなみに、クラスAの記述をメインPHPに記述すると、正常に動きます。 外部ファイルのクラスを正常に動かすにあたって、何かphp.iniあたりの編集が必要なのでしょうか? どうぞよろしくお願いいたします。

    • 締切済み
    • PHP
  • PHPでサブクラスからスーパクラスのprivate

    メンバにアクセスできる件について PHPでスーパークラスで定義したprivateのメンバにサブクラスからアクセスできる件について 質問です。 class TestClass { private $value01 = "スーパークラスの private メンバ"; public function testMethod01 () { print "スーパークラスのパブリックメソッド"; print "<h1>{$this->value01}</h1>"; } protected function testMethod02(){ print "スーパークラスの protected メソッド"; } private function testMethod03(){ print "スーパークラスの private メソッド"; } public function getMethodList(){ print_r(get_class_methods($this)); } } class ExClass extends TestClass{ private $value01 = "サブクラスの private メンバ"; } $obj = new ExClass(); $obj-> testMethod01(); と上記のようにサブクラスのインスタンスから継承したpublicなメソッド testMethod01()を実行すると スーパークラスのprivateなプロパティにアクセスできてしまいます。 これってどういうことでしょうか?privateメンバってそのクラスの中からだけしかアクセスできませんよね? 上記では、サブクラスからアクセスしているような状態にみえますがどういうことでしょうか? ご教授御願い致します。

    • ベストアンサー
    • PHP
  • クラス名やモジュール名の競合について

    プログラミング言語のRubyでプログラムを作っていて疑問に思った事がありますので どなたかご存知の方が居れば教えてください。 Rubyにおいては同じクラス名やモジュール名であっても モジュール内に対象クラスやモジュールを定義する事で 「モジュール名::クラス名」等と言う参照が可能になっていますよね そこで気になったのですが、同名のクラスAとモジュールAがある場合に (つまりクラスAの名前=モジュールAの名前) class モジュールA::クラスB  # コンストラクタ  def initialize   @prop = クラスA.new  end end 等と記述すると、コンストラクタの内部の記述において クラスAの名前とモジュールAの名前が競合するので、クラスBの生成時にエラーが発生します。 この様なケースにおいて、コンストラクタの内部でクラスAのインスタンスを 正しく生成する方法はあるのでしょうか? 勿論前提として、クラスAは他のモジュールに含まれたクラスではありません。 Javaの様にパッケージ概念があって、全てのクラスについて何らかのパッケージに所属している等の 仕組みが無いので、時々この様な命名をしてしまい困る事があるので この様なケースを回避する方法についてご存知の方が居れば、教授ください。 よろしくお願いします。

  • 「Re:Re」の返信は「Re2:Re」で

    携帯メールのやり取りで、どれがどの返信か分からなくなったのですが、 「Re:Re:○○」の返信は「Re2:Re:○○」ですか?よろしくお願いします。 (○○とは件名のことです。)

  • Re:Re:となるのを Re2: というふうにするには

    ドコモの携帯を使っています。 返信をつづけているとRe:Re:とつづくと思いますが あれをRe2: というふうに自動的になる設定方法はありますか。

  • 引き渡しについて教えてください

    注文で家を建て、やっともうすぐ引き渡しというところまで来ています。 そんなときに監督さんから電話がきて、ベランダの壁のサイズ(高さ)を間違えたとの事。 完成検査の時には「後で手すりを付ける」ということで大丈夫ですとおっしゃられたのですが どうしても手すりをつけたくないのです。 外観のデザインを主人はとても気に入ってお願いしたはずなのに,いきなりの変更に戸惑って おります。 こういう場合は工事のやり直しをお願いするべきなのでしょうか?