OKWebでは自己フォローができないみたいなので,改めます.QNo.63140,PHPカテゴリでの通しNo.32の質問の続きです.って言うか自己レス.

 質問文中で大きな間違いをしているのがとても恥ずかしいので,訂正します.

> setCookie( "cookie", serialize($obj), mktime("2010/8/1 00:00:00") );

 mktime()ではなく,strtotime()です.何をやってるんだ俺は.

 それから,実験ですが,オブジェクトのunserialize()時に同名のクラスの定義があっても,そのクラスのインスタンスとしては取り扱ってくれませんでした.

 せっかくserialize()時にクラス名まで保存しているんだから,同名のクラス定義があったら読みに行ってくれたらいいのになぁ.

 という,ぼやき混じりの無意味な自己レスでした.以上.回答してくださった方(a-kumaさんだけ?),どうもありがとうございました.

このQ&Aに関連する最新のQ&A

A 回答 (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++な感じで組んでると痛い目を見ることは確かです(^^;

この回答への補足

 まず,非常にご丁寧なご返事に感謝します.ここまで教えていただけるとは思っていませんでした.いまさらこんなことを言ってしまうとご気分を害されるかもしれませんが,質問内容が途中から(アルバイトの)仕事とは関係のない,興味本位のものになっていました.申し訳ありません.ひょっとして気づいておられたかもしれませんが,それでも付き合っていただいたことに,お礼を申し上げます.

 ご返事をいただいてから「しまった!」と思ったのですが,本来避けるべき手取り足取りのご返事をいただくような質問をして,少し反省をしております.

> ページの最初に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()がありさえすれば
// エラーは出ない

 あたりまえのことでした.これが型チェックがないことの副作用か,ポリモーフィズムへの指向かは知りませんが.(ひょっとして僕は「多態性」を誤解してますでしょうか?)

 いずれにせよ,今回の質問ではいちいち丁寧なご回答をいただき,本当に感謝しております.ありがとうございました.

補足日時:2001/04/18 01:12
    • good
    • 0

つい先日まで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/

この回答への補足

> その中でclassのsirialize、unsirializeもしてましたよ
> やり方はserializeでクラスの内容を読みこみ
> 再構築コードを文字列として作成し、unserialize時に
> それをevalする、と言う手法を取っていました

 なるほど.とりあえずphpの標準ライブラリの仕様はそんなに読み込んでいないので,具体的にどういうコードになっているのかちょっと想像がつきませんが,「読めば多少は理解」出来そうな感じ(ほんとか?)ですね.
 それでは,読ませていただきます.

 「ひとりごと」.

 PHPLIBのserialize()は,確か特定のクラスのメソッドとして実装されていましたよね・・・.そのクラスの各サブクラスは,serialize()を各々オーバーロードしてたんでしょうか・・・,それとも,元のserialize()がある程度各クラスに対してポータブルにかかれていたんでしょか?.

 そう言えば,クラス間キャストが出来ないとなると,いわゆる「多態性」ってやつはどうなるんですか?.

補足日時:2001/04/16 13:33
    • good
    • 0
この回答へのお礼

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

お礼日時:2001/04/16 13:45

> 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自身で実装できそうですか?.

補足日時:2001/04/16 13:19
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aと関連する良く見られている質問

Q画像ファイル(.bmp, gif, .jpg, .png)など縦横サイズを取得する方法

PHP5でホームページにある画像ファイル(.bmp, gif, .jpg, .png)など縦横サイズを取得する方法はありますか?

例えば、Yahooのロゴ
http://k.yimg.jp/images/top/sp/logo.gif
は、221px, 59pxm GIFnなので、以下のように取得したいです。

$ret = hogehoge???($url);

echo $ret["width"]; // 221px
echo $ret["height"]; // 59px
echo $ret["type"]; // gif

Aベストアンサー

http://jp2.php.net/getimagesize
GDライブラリの、getimagesize関数を使えばいけそうです。

Q$test = array(80,60,22,50,75);を(22,60,80,50,75);変更

https://oshiete.goo.ne.jp/qa/9231613.html から
 $test = array(0=>80,1=>60,2=>22,3=>50,4=>75); のご回答をもとに
$test = array(80,60,22,50,75);を$test = array(22,60,80,50,75);に変更しました。
 結果が”最高得点22です。”と予想しておりました・・しかし、変わらずに
 ”最高得点は80です。”のままでした!?この場合ですが、考え方はとしまして、
 $test = array(2=>22,1=>60,0=>80,3=>50,4=>75);となったので、以上の結果となっ
との考えで間違いないでしょうか?
 よろしくお願いいたします。

Aベストアンサー

表現は未熟ではありませんが、Campus2さんがどのような思考をしているのかという意味で
国語の問題に近いと言っただけですのでご了承を〜

ちなみに今回のはキーに関しては何でもいいのです。
以下のコードでも最高点は80と出力されます。

<?php
//$test = array(80,60,22,50,75);
$test = array("apple"=>80,"tomato"=>60,"banana"=>22,"milk"=>50,"cake"=>75);

$max = 0;

foreach($test as $id => $value){
if($max < $value) $max = $value;
}

print "<p>最高得点{$max}です。</p>";
?>

また$id => $valueも関係性を示しているだけなので、
foreach文は以下のようにも記述できます(紛らわしいのでこんな書き方しませんが)。

foreach($test as $aaa => $bbb){
if($max < $bbb) $max = $bbb;
}

///////////////////////////////////////////

過去の質問
https://oshiete.goo.ne.jp/qa/9200257.html
でも答えましたが、

例えば配列
array("22","80", "75","60","50")
はキーを何も指定しない場合以下と同じになります。
array('0' =>"22",'1' =>"80", '2' =>"75",'3' =>"60",'4' =>"50");

array("50","80", "75","60","22")
と並び変えても
array('0' =>"50",'1' =>"80", '2' =>"75",'3' =>"60",'4' =>"22");
のままです。

表現は未熟ではありませんが、Campus2さんがどのような思考をしているのかという意味で
国語の問題に近いと言っただけですのでご了承を〜

ちなみに今回のはキーに関しては何でもいいのです。
以下のコードでも最高点は80と出力されます。

<?php
//$test = array(80,60,22,50,75);
$test = array("apple"=>80,"tomato"=>60,"banana"=>22,"milk"=>50,"cake"=>75);

$max = 0;

foreach($test as $id => $value){
if($max < $value) $max = $value;
}

print "<p>最高得点{$max}です。</p>";
?>

また$id => $value...続きを読む

Q同一クラスに同名メソッドは可能???

現在AAAというクラスにBBBと言うメソッドを作っており、
BBBには現在引数がないのですが、
引数がある場合の処理を書きたい為、
function BBB($xxx)
を作りたいと思っておりますが普通に書くだけではエラーになってしまい、
どうにかエラーにならずに書く方法があればと思い質問させて頂きました。
宜しくお願いします。

Aベストアンサー

class AAA{
function BBB($xxx = ""){
}
}
じゃ、だめ?

Qsetcookie

掲示板を作成しています。
記事を投稿した際に名前とパスワードをクッキーに保存しようとしているのですが、
何度やってもエラーになります。

$expire = time() + 30*24*3600;
setcookie("cname", $_POST['name'], $expire);
setcookie("cpass", $_POST['pass'], $expire);

現在はこのように記述しているのですが、setcookieの部分両方でエラーが出ます。
色々書き直したりもしたのですがどうしてもうまくいかず…
どこが間違っているのでしょうか?
アドバイスをお願いします<(_ _)>

Aベストアンサー

 見たところ、setcookie()の記述に間違いは無いように見えます。
 ただ、cookie は HTTPプロトコルの制約上、他のあらゆるhtml文の出力より先に送信しなければなりません。(HTTPヘッダー部分で送信する必要があります)
 ですので、setcookie()を行う前に print()文や
?>
<html>
<head>
:
<?php
 等、出力を行っていないでしょうか。先に出力を
行っていると、エラーが出たと記憶しております。

Qsetcookie関数について

お世話になっております。

Setcookie関数で、「有効期限をブラウザを閉じるまで(セッションの最後)」かつ「クッキーを有効としたいパス」かつ「クッキーが有効なドメイン」を設定したいのですが、引数をどう設定すれば良いか分かりません。

現在は下記のように1日だけCokkieを有効にしてます。
setcookie("user_id",$user_id,time()+60*60*24*1,"/","192.168.134.249");

ブラウザが閉じるまでの設定は
(例) setcookie ("TestCookie", $value);
上記の通り有効期限を空にすれば良いとオフィシャル情報ではありますが、パスとドメインの設定は必須なのでパスとドメインを入力するとエラーが出ます。

その時のSetcookieの引数は下記の通りです。
setcookie("user_id",$user_id,"/","192.168.134.249");
↑有効期限を抜いた

どうかご教授お願い致します。

Aベストアンサー

> setcookie("user_id",$user_id,"/","192.168.134.249");
これでは抜いたことにはならないと思います。
"/" が有効期限に設定されてしまいます。

省略の仕方は、マニュアルにも記載されています。

>引数name以外の全ての引数はオプションです。
>全ての引数に関して引数の指定をスキップするために空文字列 ("")とすることが可能です。
>expireおよび secure 引数 は数値なので、空文字列でスキップすることはできません。
>代わりにゼロ (0)を使用してください。

参考URL:http://php.s3.to/man/function.setcookie.html


このカテゴリの人気Q&Aランキング

おすすめ情報