2011-05-20 7 views
3

私は、このUserクラスさて、今私は私のistanceの参照を格納する必要がある場合には(我々は、単一のHTTP要求のために話をしているので、もちろん)私は1つの以上のユーザーログインを持つことはできません考慮Userクラスの一意のインスタンスに使用するパターンはどれですか?

class User{ 
    private $logged = false; 
    private $id; 

    public function User() { 
     //> Check if the user is logged in with a cookie-database and set $logged=true; 
    } 

    public function isLogged() {} 
    public function editPerms() {} 

    //> other methods  
} 

を持っています?

これはシングルトンが有用であろうが、これらの日、誰もがシングルトンは(静的メソッドように)悪であると言う場合です。

は私が $GLOBALS['currentUser'] = new User();行うと、どこでも、それはづけしたが、私は、これはシングルトンよりも悪いと思うことができました。

どうすればいいですか?
私はを要求する必要はありません。リクエストの間にこのインスタンスを保存してください。 同じリクエスト内でフレームワーク内のこのインスタンスにアクセスする方法が必要です。

あなたは私は私のヘルパーオブジェクトのすべてのために今何をすべきかを知りたい場合は、サービスコンテナ(それは同様に悪いと考えられています)です:

function app($class) {  //> Sample 
    static $refs = array(); 

    if (!isset($refs[$class])) 
     $refs[$class] = new $class(); 

    return $refs[$class]; 
} 

//> usage app('User')->methods(); 

(IE何symfony does)なぜ

+0

あなたはシングルトン・パターンとグローバル変数の両方が1つの要求内でのみ有効であることを、知っていますか?セッション、クッキー、ファイル、またはデータベースに格納されていないものはすべて、リクエスト間で失われます。 – KingCrunch

+0

はい、私はそれで完璧です。ユーザーがログインしているかどうかを確認する必要があります。しかし、しないでくださいOT –

+0

しかし、あなたの質問は絶対に意味がありません:あなたは(グローバルまたはシングルトンを介して)ユーザーを "保存"することを考えていますが、要求の間に失われる)。また不可能なことに、複数のユーザーが1回のリクエストでログインすることができます。 – KingCrunch

答えて

6

以前は成功したソフトウェア抽象化のライブラリのように、パターンは参考になるはずです。あまりにもしばしば、今日は、パターンが、プログラムの文脈にかかわらず、物事が「正しい」か「間違っている」のような何らかの宗教であるとみなしています。

達成したいことを考えて、あなたに合った方法でマップしてください。このパターンとそのパターンとの間の微妙な違いを抱かせることは、そのポイントを逃してしまい、あなたのプログラムを書くことはできません。 Learn by しています!

HTH。

1

わかりませんすべての議論の上に私には完全に合理的な質問のようです。

ここで重要なのは、Userクラスの静的メンバーを使用することです。静的メソッドにかかわらず、いくつかは言うかもしれないものの、あなたの友達です:

class User 
{ 
    private $logged = false; 
    private $id; 

    private static $_currentUser; 
    public static function currentUser() 
    { 
    if (empty(self::$_currentUser)) 
    { 
     @session_start(); 
     if (array_key_exists('current_user', $_SESSION)) 
     { 
      self::$_currentUser = $_SESSION['current_user']; 
     } 
     else 
     { 
      // force login in or whatever else. 
      // if you log in, make sure to call User::_setCurrentUser(); 
      return null; //or some special 'empty' user. 
     } 
    } 
    return self::$_currentUser; 
    } 
    // you may consider making this public, but it is private because it is a bit 
    // more secure that way. 
    private static function _setCurrentUser(User $user) 
    { 
    self::$_currentUser = $user; 
    $_SESSION['current_user'] = $user; 
    } 

    public function User() { 
    //> Check if the user is logged in with a cookie-database and set $logged=true; 
    } 

    public function isLogged() {} 
    public function editPerms() {} 

    //> other methods  
} 

// Usage 
$pUser = User::currentUser(); 
+0

ありがとう、しかし、私は要求の間にそれを保存する必要はありません。私はちょうど1つの要求のためだけに私のフレームワークでグローバルにアクセスできるように方法が必要です – dynamic

+0

これはそうです。 User :: currentUser()を呼び出すだけです。それは静的なので、既に設定されている場合は、あなたは良いです。 –

+0

はい、私は静的メソッドとシングルトンを使用しないでください。参照:http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/詳細について – dynamic

1

Misko Heveryの影響は、私にはかなり強いです。彼の新しい注射可能な区別もそうです。ユーザーは注射可能ではなく、新しいものである。ユーザーの責任:ユーザーがログインしているかどうかを自分自身に伝える必要がありますか?同様の問題について彼が話しているところにはポストがあります:クレジットカードとチャージ(自己?)。あなたがそれをしたいと思い、何シングルトンについての記事であることを起こる:

http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/

彼が上で持っているものの権限、ユーザーがログインしているかどうかをチェックするためのサービスにそれを残すだろうとサイト。

あなたのアーキテクチャが変更され、問題が異なる(ユーザーの周りを回っていますか?どこに必要ですか?「ユーザーがログインしています」サービスへのアクセス方法...) 。

+0

'ユーザーの周りを回っていますか? '確かに私はそれを行う最良の方法を尋ねています – dynamic

+0

これはアプリケーションによって異なります。あなたはCredentials、Preferences ...を持っているかもしれないことに注意してください。あなたもそれらを使うことができます。デメテルの法律を特に気をつけてください。仕事をするために必要なものだけを渡す。オブジェクトへのグローバルなアクセスが必要な場合は、改善できるものがあります。 – koen

+0

は 'あなたがオブジェクトへのグローバルアクセスする必要がある場合であってもsymfonyのをimproved'することができるものは存在しないです:http://symfony.com/doc/2.0/book/service_container.html – dynamic

3

シングルトンは悪くありません。シングルトンの悪い使用法は悪です。人々がこのパターンをあまり嫌うようになった理由(それはどんなものでも、それを反パターンと呼んでも)は、不適切な使用によるものです。

経験の浅い人が多すぎると、彼らはクラスのインスタンスを2つ以上必要としないことを発見します。しかし、問題は、クラスのインスタンスが1つだけ必要な場合ではなく、複数のインスタンスがコードを壊すかどうかということです。だから自分自身にこの質問をしてください。もしUserインスタンスがもっとあれば、あなたのコードは壊れますか?そうでなければ、おそらくあなたは気にしないでください。 :)

シングルトンの正当な使用があります。疫病のようなこのパターンを恐れ、いつも悪いことがあると考えている人がいます。私よりもはるかに経験豊富なプログラマーの言葉で、「シングルトンはモルヒネのようなものです。彼らはあなたに本当の後押しを与えることができますが、間違った方法で使うと問題になります。あなたがシングルトンが良い選択になることができるときに私がいくつかの詳細に入るようにしたいなら、この答えにコメントを残してください。 :)

+0

人が良いです。しかし、なぜそれを試してみてください – dynamic

+0

@ yes123絶対に!シングルトンの最も普及した使用法であるロガーシステムはどうですか?シングルトンの使用を拒否するのは、一般的には避けて、実際にあなたの人生と他の人の生活をより楽にすることができるということを無視するならば、私は本当に何を言いたいのか分かりません。シングルトンが常に悪くないわけではないと私はこのスレッドで唯一の人ではない。 –

+0

通常、静的メソッドはすべて単調であるため、すべての静的メソッドが正常である場合は、Loggerが該当します。しかし、ロガーを除いて、多くの他の一方向クラスはありません – dynamic

2

コンテキストがないと建築的な質問に答えることは常に困難です。この場合、Userオブジェクトがどのように永続化されているか(どこから来たのか)、クライアントコードがどのように整理されているかが非常に重要です。私はMVCアーキテクチャを想定しています。なぜなら、今日は流行っているからです。また、私はあなたのユーザーオブジェクトは、ここではいくつかのアクセス許可の制御について言及している認証としてだけ多くの責任を負うだろうと思うが、それでもまだ十分ではありません。

私はサービスに認証責任を押し付け、必要に応じてそれを渡します。ここにいくつかのサンプルコードがあります。

class AuthenticationService { 
    /** 
    * @var User 
    */ 
    private $currentUser; 

    public function __construct(Request $request) { 
     // check if the request has an user identity 
     // create a user object or do nothing otherwise 
    } 

    public function getCurrentUser() { 
     return $this->currentUser; 
    } 
} 

class User { 
    public function editPerms(){} 
} 

// the client code 
class Controller { 
    private $auth; 

    public function __construct(AuthenticationService $auth) { 
     $this->auth = $auth; 
    } 

    public function handleRequest() { 
     $currentUser = $this->auth->getCurrentUser(); 

     if ($currentUser === null) { // of course you could use Null Object Pattern 
      // no user is logged in 
     } 

     // do something with the user object 
    } 
} 

あなたの質問に対する答えは、あなたのアプリケーション全体を通して適切な依存性注入が必要なことです。サーバーから取得する唯一のオブジェクトはリクエストです。依存性注入コンテナはそれをAuthenticationServiceに注入し、後者はコントローラに注入されます。シングルトンはなく、静的メソッドもグローバル変数もありません。依存関係はDIコンテナで追跡され、必要に応じて注入されます。また、DIコンテナは、サービスが一度だけインスタンス化されるようにします。

Container-Managed Application Design, Prelude: Where does the Container Belong?」という記事は、いくつかのDIの概念を明らかにする場合があります。

+0

あなたの素晴らしいご意見ありがとうございます。私の文脈に関しては、それはmvcではありません。それは、rasmusのようなフレームワークのようなものではありません。http://toys.lerdorf.com/archives/38-The-no-framework-PHP-MVC-framework.htmlだからこそ私はこれらのアイディアをどこに保存するのか分かりません。 – dynamic

+0

コードこの小さな記事では、多くのOOPとアプリケーションアーキテクチャのベストプラクティスを解説しています。あなたが質問で言及した2つの記事と互換性がありません。リーンで再利用可能なパターンを構築して、要件を満たすことができるという主な考えは絶対に有効ですが、 – dypsilon

0
  1. 他の誰もがこれに重点を置いているので、シングルトンは邪悪ではありません。 私は "嘘つき"の記事を読んでいて、彼は非モジュラーデザインと依存性の低い継承の人為的な例を使用しています。

シングルトンファクトリパターン(Auth)は、Userクラスを返すlogin()メソッドと、そのユーザーのHTTPリクエスト間の状態を保存するメソッドを提供します。

これには、セキュリティ機能とセッション機能をユーザー機能から分離するメリットがあります。さらに、工場を使用して、あなたはデシベルを検討する前に、

class auth { 
    private static $auth = null; 
    private $user = null; 

    // must use getAuth(); 
    private __construct(){}; 

    public getAuth() { 
     if (is_null($this->auth) { 
      $this->auth = new auth(); 
     } 
     return $this->auth;  
    } 

    public function login($user,$pass) { 
     ... // check db for user, 

     if ($dbrow->user_type == 'admin') { 
      $this->user = new admin_user($dbrow); 
     } else { 
      $this->user = new normal_user($dbrow); 
     } 

     $this->user->setSession($db->getsession()); 
    } 

    public function getUser() { 
     return $this->user; 
    } 

    public function saveSession() { 
     // store $this->user session in db 
    } 

    public function saveUser() { 
     // store $this->user changes in db 
    } 
    ... 
} 

ユーザークラス自体は、単にセキュリティを強化する、データ構造となっ要求するオブジェクトかを理解する必要がシステムの残りの部分を持たないユーザの複数のタイプを持つことができ、ビジネスルール、および出力目的のために一部のデータの書式設定を行うことができます。

class normal_user extends user { 
    ... getters and setters 
    public function getName() {} 
    public function setEmail() {} 
    public function setprofile() {} 
} 

すべてのデータベース、状態およびセキュリティ上の懸念は、認証に集中しています。 ユーザーオブジェクトを作成する唯一の方法は(正式に)auth-> login()を実行することです。

あなたはまだ

$me = new normal_user(); 
$me->setName(); 
echo $me->getName(); 

を行うことを許可されますが、それは$ auth->ユーザーに参照されていないので、デシベルでこれを保存するための新たなコーダのための方法はありませんされています。

あなたが(サインアップに)新しいユーザーを作成するために、ユーザーオブジェクトを消費するには、authで関数を作成することができます

... 
public function create(user $user) { 
    // validate $user 
    $this->user = $user; 
    $this->saveUser(); 
} 
... 

あなたはちょうどあなたが、実行の終わりに保存した機能を実行することを確認する必要があります...デストラクタでおそらく ()

シンプル

+0

基本的にあなたのクラスAuthはユニークなクラスUserのコンテナですか? (あなたが 'new normal_user()を書いたとみなすと、この平均クラスUserはシングルトンではありません) – dynamic

+0

oops。申し訳ありませんが、ユーザーはシングルトンではありません...認証は、それを反映するように編集されています。ユーザーは単なる栄光の構造体です。 authはユーザを作成/保存する唯一の方法であり、利用できる唯一のメソッドはlogin()です。プログラマからの遵守を強制します。 –

関連する問題