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


188

$ _SESSIONにオブジェクトを実際に格納できることがわかりました。別のページにジャンプしてもオブジェクトが残っているので、とても便利です。このアプローチを使用する前に、本当に良いアイデアなのか、潜在的な落とし穴があるのか​​を確認したいと思います。

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

だから、要するに:それはセッション内のストアオブジェクトにOKですが、それで何か問題があるのですか?


編集:

一時的な要約:データベースのクエリが再度行われる場合でも、オブジェクトを再作成するがおそらく良いことだと私は理解しています。

さらなる答えは、おそらくその側面についてもう少し詳しく説明できるでしょう!


13
私が2008年にどれほど「ばかげた」か:-)
markus

49
しかし、2014年に私たちのように「愚か」に役立つ質問:D
Momin Al Aziz

3
あなたがマルクスに尋ねた非常に素晴らしい質問.. :)私は今日それを読みました;)
gkd '27

1
あなたは愚かではなかった!あなたは私に何を尋ねようとしているのか尋ねて、10年後、私をしっかりしました!
toddmo 2018年

まあ、私はあなたが私を愚かな質問をすることから私を救ったと思います2019
Maxwell

回答:


133

私はこのトピックが古いことを知っていますが、この問題は引き続き発生し、私の満足に対処できませんでした:

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

私は特に、ハンク・ゲイが出した「ダブル・ワーミー」の議論によって受けた祝福に心を震わせています。OPは分散型で負荷分散されたeコマースシステムを構築していますか?私の推測はノーです。さらに、彼の$ Userクラスなどをシリアル化しても、サーバーが修復不能になることはないと断言します。私のアドバイス:アプリケーションに適した手法を使用してください。$ _SESSION内のオブジェクトは問題なく、常識的な予防措置の対象となります。アプリが突然、提供されるトラフィックでAmazonに匹敵するものに変わった場合は、再適応する必要があります。それが人生だ。


16
これまで読んでいる私自身の考えの多くを組み込んだ良い答えです。現代のインターネットに状態が必要です。一部のアプリケーションは状態を必要とせず、ステートレスな方法で作成することが理にかなっていますが、現代のインターネットは状態(AKA:ログイン!)に基づいているシステムを多用しすぎて、あきらめています インターネットの偉大な神々は、その基本的な概念を長年にわたってCookieの形式で組み込んでおり、基本的なレベルでは、ローカルストレージの形式でHTMLに追加しています。一部のアプリケーションでは状態の過度の使用を回避することは理にかなってますが、一部の!=すべて!
RonLugge 2012年

さて、私が人が発砲した直後にその質問をしたとき、私は今日私が知っている多くのことを知りませんでした...それも同様です。それまでの間、いくつかの良いユースケースがあるかもしれませんが、一般的には最初に他のソリューションを探します。他の回答はカテゴリー的であるため、これを新しい承認済み回答としてマークします。
マーカス2013

答えがほとんどないので、私は大声で笑います。これはしました。ブラボー+1
toddmo 2018年

114

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


12
ありがとう!これでバグが修正されました:D
Matt Ellen

適切な__autoload()機能があれば、この問題は回避できると思います。
Langel 2013年

シリアル化されたオブジェクトのシリアル化解除では、クラス定義を追加する必要がありますか?オブジェクトのシリアル化時にクラス定義が必要であることに同意しますが、シリアル化されたオブジェクトのシリアル化を解除する必要があるファイルにもクラス定義を追加する必要がありますか?
Rajesh Paul

35

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

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

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

以上のことから、セッションに入力する情報が多いほど、パフォーマンスへの影響が大きくなります(Vinkoが指摘)。また、Vinkoが指摘しているように、オブジェクトがシリアライズ可能でない場合、セッションは正しく動作しません。したがって、経験則として、セッションに絶対に必要以上のものを入れることは避けてください。

@Vinko通常は、追跡しているデータを返信に埋め込んでクライアントに再送信させることで、サーバーにストア状態を保持させます。たとえば、非表示の入力でデータを送信します。あなたがいる場合、実際に状態のサーバ側の追跡を必要とする、それはおそらくあなたのバッキングストアにする必要があります。

(Vinkoは追加します:PHPはデータベースを使用してセッション情報を保存でき、クライアントに毎回データを再送信させることで潜在的なスケーラビリティの問題を解決できる可能性がありますが、クライアントがすべてを制御できるようになるため、注意が必要な大きなセキュリティ上の問題が発生しますあなたの状態)


1
HTTPレベルでのセッションの概念はありません。サーバーはこれを提供するために、クライアントに一意のIDを与え、リクエストごとにクライアントに再送信するようにクライアントに通知します。次に、サーバーはそのIDをSessionオブジェクトの大きなハッシュテーブルへのキーとして使用します。続きます…
ハンクゲイ

1
サーバーはリクエストを受け取ると、クライアントがリクエストで送信したIDに基づいて、セッションオブジェクトのハッシュテーブルからセッション情報を検索します。この余分な作業はすべて、スケーラビリティの二重の欠点です(HTTPがステートレスである主な理由)。...つづく
ハンクゲイ

1
どういうわけか、状態を溶接せずにHTTP経由で複雑なアプリケーションを実装するにはどうすればよいのでしょうか
Vinko Vrsalovic '25 / 09/25

3
回答を編集して、これらすべてのコメントを含めてください。重要なすべてがコメントにある場合、ウィキは読みやすく、Wikiの方が優れています。とにかく、私はあなたの回答を受け入れられたものとして選択することはできません。ありがとう!
マーカス2008

6
「ワーミー・ワン」もっとこれに投票できたらいいのに。あなたのタイミングを知っています。メモリ参照のコストは100ナノ秒、つまり0.0001ミリ秒です。そのため、メインメモリに格納されているハッシュテーブルでルックアップを実行しても、時間はかかりません。O(1)あなたに何かを伝えますか?@whammy two:ランダムなサーバーにすべてのリクエストをランダムにルーティングしないのですか?ラウンドロビンを行い、同じユーザーから同じサーバーへのルーティングを維持します。これはすごい、超明白です。あなたは本と30以上の賛成投票すべてに戻る必要があります
Toskan

19
  • シリアル化できないオブジェクト(またはシリアル化できないメンバーを含むオブジェクト)は、期待どおりに$ _SESSIONから取得されません
  • 巨大なセッションはサーバーに負担をかけます(状態のメガをシリアル化および非シリアル化するたびにコストがかかります)

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


9

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


リクエストごとにデータの5x2テーブルをクエリすることと、セッションで結果をキャッシュしてそれを使用することの間のパフォーマンスに関するコメントはありますか?
musicliftsme

6

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


では、すべてのデータベースクエリの再実行を含めてオブジェクトを再構築する方が良いでしょうか?これを行うことに対する私の考えの1つは、同じものについて再度dbをクエリする必要がないということでした。
マーカス'09 / 09/25

3
データベースに対してクエリを実行しないことが重要な場合は、セッションに保存するのではなく、キャッシュを使用します。ただし、キャッシングの構築などを行う前に、それが本当にパフォーマンスへの影響かどうかを確認してください。
ジョニー

ありがとう、私は実際にはそうではないと思います。もう一度クエリを実行します。
マーカス2008

4

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

また、セッションのサイズも考慮してください。セッションの格納方法によっては、サイズ制限や遅延の問題が発生する可能性があります。


0

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

とにかく、あなたがあなたの修正で提案するように、私はオブジェクトを再作成することも良いと思います。したがって、おそらくidを格納し、リクエストごとにデータベースからオブジェクトをプルする方が安全です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.