web-dev-qa-db-ja.com

PHP:「オブジェクト」を$ _SESSION内に保存する

実際にオブジェクトを$ _SESSIONに保存できることがわかりました。別のページにジャンプしてもオブジェクトが残っているため、非常にクールです。このアプローチの使用を開始する前に、それが本当に良いアイデアであるかどうか、またはpotential pitfallsが含まれているかどうかを確認したいと思います。

単一のエントリポイントがあれば、それを行う必要はありませんが、まだそこにいないので、単一のエントリポイントがなく、本当にオブジェクトを保持したいので、そのような私の状態を失う。 (現在、ステートレスサイトをプログラムする必要があることも読みましたが、その概念はまだ理解していません。)

要するに:セッションにオブジェクトを保存しても大丈夫ですか、何か問題はありますか?


編集:

一時的な要約:今では、データベースを再度照会する場合でも、おそらく再作成した方が良いオブジェクトであることを理解しています。

それ以上の答えは多分その側面について詳しく説明するもう少し!

182
markus

私はこのトピックが古いことを知っていますが、この問題は引き続き発生しており、満足のいくものではありません。

オブジェクトを$ _SESSIONに保存するか、非表示のフォームフィールドに格納されたデータに基づいて布全体を再構築するか、毎回DBからオブジェクトを再クエリするかは、状態を使用しています。 HTTPはステートレス(多かれ少なかれ、ただしGET対PUTを参照)ですが、Webアプリでやりたいことのほとんどすべては、どこかで状態を維持する必要があります。あたかも国家を隅々まで追い詰めるような行為は、ある種の理論上の勝利に相当するだけである。状態は状態です。状態を使用すると、ステートレスであることによって得られるさまざまな技術的利点が失われます。これは、睡眠を失うべきであることを事前に知らない限り、睡眠を失うものではありません。

ハンク・ゲイが提唱した「ダブル・ワミー」の議論が受けた祝福に特に戸惑っています。 OPは、分散され負荷分散された電子商取引システムを構築していますか?私の推測はノーです。さらに、彼の$ Userクラスなどをシリアル化しても、修復できないほどサーバーに障害が発生しないと仮定します。私のアドバイス:あなたのアプリケーションにとって賢明なテクニックを使用してください。 $ _SESSIONのオブジェクトは、常識的な予防措置の対象となります。アプリが突然トラフィックのトラフィックでAmazonに匹敵するものに変わった場合、再適応する必要があります。それが人生。

128
shanusmagnus

session_start()呼び出しが行われるまでに、クラスの宣言/定義がPHPによって既に検出されているか、既にインストールされているオートローダーによって検出される限りは問題ありません。そうしないと、セッションストアからオブジェクトを逆シリアル化できません。

112
cruizer

HTTPは、理由のためにステートレスプロトコルです。セッションは状態をHTTPに結び付けます。経験則として、セッション状態の使用は避けてください。

更新:HTTPレベルでのセッションの概念はありません。サーバーは、クライアントに一意のIDを付与し、すべてのリクエストで再送信するようにクライアントに伝えることでこれを提供します。次に、サーバーはそのIDをSessionオブジェクトの大きなハッシュテーブルへのキーとして使用します。サーバーがリクエストを受け取ると、クライアントがリクエストで送信したIDに基づいて、セッションオブジェクトのハッシュテーブルからセッション情報を検索します。この余分な作業はすべて、スケーラビリティに関する二重の不利益です(HTTPがステートレスである大きな理由)。

  • Whammy One:単一のサーバーでできる作業を減らします。
  • Whammy Two:古いサーバーにリクエストをルーティングすることはできないため、スケールアウトが難しくなります。すべてのサーバーが同じセッションを持つわけではありません。特定のセッションIDを持つすべてのリクエストを同じサーバーに固定できます。これは簡単なことではなく、単一障害点です(システム全体ではなく、ユーザーの大部分にとって)。または、クラスター内のすべてのサーバーでセッションストレージを共有できますが、ネットワーク接続メモリ、スタンドアロンセッションサーバーなど、より複雑になりました。

これらすべてを考えると、セッションに入れる情報が多いほど、パフォーマンスへの影響は大きくなります(Vinkoが指摘しているように)。また、Vinkoが指摘するように、オブジェクトがシリアル化できない場合、セッションは誤動作します。そのため、経験則として、絶対に必要以上のものをセッションに入れないでください。

@Vinko通常、送信する応答に追跡しているデータを埋め込み、クライアントに再送信させることで、サーバーストアの状態を回避できます。たとえば、非表示の入力でデータを送信します。 本当にサーバー側で状態を追跡する必要がある場合は、おそらくバッキングデータストアにあるはずです。

(Vinkoが追加:PHPはセッション情報を保存するためにデータベースを使用でき、クライアントが毎回データを再送信することで潜在的なスケーラビリティの問題を解決できるかもしれませんが、セキュリティ問題の大きな缶を開きます。クライアントがあなたのすべての状態を管理しています)

35
Hank Gay
  • シリアル化できない(またはシリアル化できないメンバーを含む)オブジェクトは、予想どおり$ _SESSIONから出てきません。
  • 巨大なセッションはサーバーに負担をかけます(毎回の状態のシリアル化とシリアル化解除は高価です)

それ以外は問題はありません。

18
Vinko Vrsalovic

私の経験では、いくつかのプロパティを持つStdClassよりも複雑なものには一般的に価値がありません。シリアライズ解除のコストは、セッションに格納された識別子を指定してデータベースから再作成する場合よりも常に高くなっています。クールに思えますが、(いつものように)プロファイリングが重要です。

9
Greg

絶対に必要でない限り、状態を使用しないことをお勧めします。セッションを使用せずにオブジェクトを再構築できる場合は、再構築してください。 Webアプリケーションに状態があると、アプリケーションの構築がより複雑になります。リクエストごとに、ユーザーの状態を確認する必要があります。もちろん、セッションの使用を避けることができない場合があります(例: webapplication)。最後に、セッションオブジェクトをできるだけ小さくして、大きなオブジェクトのシリアル化と非シリアル化のパフォーマンスに影響を与えることをお勧めします。

6
Johnny

リソースタイプ(db接続やファイルポインターなど)はページのロード間で保持されないことを覚えておく必要があり、これらを目に見えないように再作成する必要があります。

また、セッションの保存方法に応じて、セッションのサイズを考慮してください。サイズの制限や遅延の問題が発生する場合があります。

4
Marc Gear

ソフトウェアライブラリをアップグレードするときにも表示されます-ソフトウェアをアップグレードし、古いバージョンではV1ソフトウェアのクラス名とセッションにオブジェクトがあり、セッションにあったオブジェクトをビルドしようとすると新しいソフトウェアがクラッシュしました-V2ソフトウェアはそれらの同じクラスを使用しなくなったため、それらを見つけることができませんでした。セッションオブジェクトを検出し、見つかった場合はセッションを削除し、ページをリロードするための修正コードを入れる必要がありました。最初に報告されたときにこのバグを再作成していたことを気にする最大の痛み(あまりにも馴染みのある、「まあ、それは私にとってはうまくいく」:)すべてのユーザーが確実にセッションに古いセッション変数を持ち、すべてのユーザーにクラッシュする可能性があり、ひどい起動だったため、起動前にそれを見つけました。

とにかく、あなたが修正で提案するように、オブジェクトを再作成する方が良いと思います。したがって、単にidを保存してから、データベースからオブジェクトをプルする各リクエストで、より安全になります。

0
Martyn