2012-06-26 22 views
5

私は単純なORMソリューションを開発しており、扱いにくい状況に陥っています。理想的には、静的コンテキストとそれが呼び出される方法に応じてオブジェクトコンテキストの両方でメソッドを使用できるようにしたいと考えています。私はこれが可能であるかどうかわからないけど、ここで私が何を意味するかです:静的/非静的メソッドの問題

は、Userモデルがどこ(呼び出したいと言う)静的に、これは現在、例えば、正常に動作します:

$user = User::where('id = ?', 3); 

今、私はユーザーがメッセージを持つなど、関係をサポートします。この関係が確立されると、私は単純にメッセージモデルの空のコピーをユーザーモデルに保存し、外部キーを設定します。たとえば、次のように今

$user -> messages = new Message(); 
$user -> messages -> foreign_key = 'user_id'; 

、理想的には、私が呼び出すことができるようにしたい:非静的コンテキストで

$user -> messages -> where('unread = ?', 1); 

をし、$これを利用して - > FOREIGN_KEYたときに、この文脈でそう外部キーがユーザーのIDと一致するメッセージをプルするだけです。 PHPではこのようなコンテキスト切り替えが可能ですか?静的コンテキストからの$ thisへの参照は静的メソッドとしてエラーを投げ、$ thisに依存してはいけません(静的コンテキストから呼び出されると、$ thisは存在しません)

この周りの巧妙な方法?私は静的キーワードの有無にかかわらず、2つの異なるプロトタイプを持つメソッドをオーバーロードしようとしましたが、これは再宣言エラーを投げました。

+0

$ user = User :: find();外部キーが指定されていない場合、これを返すようにしたいのですか? – craig1231

+0

'find()'は 'User'クラスの(静的な)関数ですが、' find() 'は' Message'クラスのメソッドです。どちらですか?どちらも? – jedwards

+0

これは不明確な例だったかもしれませんが、質問には関係がないように見えるので、パラメータを省略しましたが、実際にどのように機能するかをより正確に表現してクリアします。 –

答えて

4

かなり遊んだ後、@ drew010で述べたStrict Standardsエラーがなくても、これを実行可能にする方法を見つけました。私はそれが好きではない、それは恐ろしいと感じるが、それは動作するので、私はとにかくこれを投稿します。

基本的な考え方は、アクセス可能にしたいメソッドをprivatestaticにすることです。その後、__call()__callStatic()のマジックメソッドを定義し、プライベート静的メソッドを呼び出します。今では、 "これは問題を解決しない、私はまだ静的な文脈で立ち往生している"と思うかもしれませんが、少しの追加のために、__call()の実際のメソッドに渡された引数に$thisを追加し、メソッドの最後の引数として使用します。オブジェクトコンテキストで$thisを参照する代わりに、独自のインスタンスへの参照を取得するために3番目の引数を参照します。

私はおそらくちょうどthis codeを見てい、非常によくこのことを説明していないよ:ビューの理論と実践的な観点から

<?php 

class test_class { 

    private $instanceProperty = 'value'; 

    private static function where ($arg1, $arg2, $obj = NULL) { 
     if (isset($obj)) { 
      echo "I'm in an object context ($arg1, $arg2): I can access the instance variable: $obj->instanceProperty<br>\n"; 
     } else { 
      echo "I'm in a static context ($arg1, $arg2)<br>\n"; 
     } 
    } 

    public function __call ($method, $args) { 
     $method = "self::$method"; 
     if (is_callable($method)) { 
      $args[] = $this; 
      return call_user_func_array($method, $args); 
     } 
    } 

    public static function __callStatic ($method, $args) { 
     $method = "self::$method"; 
     if (is_callable($method)) { 
      return call_user_func_array($method, $args); 
     } 
    } 

} 

test_class::where('unread = ?', 1); 

$obj = new test_class(); 
$obj->where('unread = ?', 2); 
+0

私は実際にこの解決策がとても好きですが、これは限界を巧みに乗り越えています。私は言語が使用されることを回避するのに必要なわけではありませんが、これは全体的なスキームにいくらかの単純さを追加します。自然言語の意図を迂回する以外に、このように使用するとパフォーマンスが低下すると思われますが、フードの下で同じであるという事実はエンドユーザーには見えません。このタイプのオーバーロードを使用しないことをお勧めする他の理由はありますか? –

+1

私がこれをやっていない最も重要な理由は、私が2年後に戻ったときに、このコードが何をするのか分からなくて、10分を費やす必要があるからです。これを行うなら、コメントしてください!パフォーマンスヒットに関してはおそらくマイクロ秒を話していますが、上記のコードではオブジェクト/クラス、パブリックなどのすべてのメソッドにアクセスできるということを心に留めておく必要があります。このようにアクセスできるメソッドのホワイトリストに対して '$ method'をチェックしてください。 – DaveRandom

+0

特にオブジェクトコンテキストで、指定された引数の数に対してさらに検証を行う必要があるかもしれません。これは、PHPが引数を渡す回数が間違っているという不平を言わないのは、それをチェックするための固定定義がないからであり、誤った引数を与えると '$ this'を引数に追加して動作する性質があるからです。引数の数は、オブジェクトが間違ったパラメータに渡されます。 – DaveRandom

4

私は、PHP標準に反することなく、その言語を使用するつもりではない形で使用しないと、これを行う方法を考えることはできません。

関数は静的であるかどうかです。はい、PHPはどちらかの方法で呼び出すことができますが、これは厳しい基準に違反します。これを行うことで逃げる唯一の理由は、staticがキーワードとして存在しない古いPHP 4コードとの下位互換性のためです。

<?php 

class Test { 
    protected $_userId; 

    public function find() 
    { 
     if (isset($this)) { 
      echo "Not static.<br />\n"; 
     } else { 
      echo "Static.<br />\n"; 
     } 
    } 
} 

$t = new Test(); 
$t->find(); 

Test::find(); 

出力は次のとおりです:静的でない

は、このコードを考えてみましょう。
スタティック。

しかし、エラー報告と、これは実際に出力され、オン:

ない静的。

厳密な基準:非静的メソッドTest :: find()は、test.phpのstatic.startでtest.phpに静的に呼び出さないでください。
静的。

メソッドをstaticとして宣言すると、どのように呼び出されても静的です。

私は答えがはいだと思いますが、あなたはこの回避策を使用して行うことができますが、私はそれをお勧めしません。双方向にしたい場合は、public function find()public static function findStatic()という2つのメソッドを追加することをお勧めします。

コードは$obj->find()またはClass::find()と書かれているので、1つのメソッドが静的に動作するのではなく、静的メソッドと非静的メソッドを同じように簡単に使用できます。 DRYを遵守するためには、実際の発見を行うために他の方法を活用する方法があると思います。

+0

あなたの返信をありがとう、私はこの結論に来ていただけでなく、私は私のテストで同じ厳しい基準のエラーを持っていた。私は静的な名前のカウンターパートを必要とする6-7の異なるメソッドを持っているのと同じ名前を使用できることを期待していました。しかし、これは確かに最も論理的な意味を持っている、私はそれを回避することができるかもしれないことを期待していた;) –

4

ご質問にはお答えできませんが、コメントには記載がありません。 あなたがやっていることは少し非論理的です。

$user->messages = new Message(); 

あなたがメッセージという変数内部単一のメッセージを作成しています。
$user->messages[] = new Message();を意味しますか?
また、クラス変数を保護します。

$user->messages->where('unread = ?', 1); 

あなたのユーザーメッセージから選択しようとしていますが、それはナンセンスです。あなたは何をすべき
は、単にあなたがUserクラスでやったのと同じである:静的にメッセージを取得し、その後、ユーザーに割り当てる:

$user->messages = Message::where('unread = ?', 1); 

あなたが特定の主を持っているメッセージのためにルックアップする必要がある場合キー、多くの句を取るように向上させることができるwhere方法、にパラメータとして渡す:私も個人的なメモを追加したいと思います

$messages = Message::where(array(
    array('unread = ?', 1), 
    array('id = ?',  $message->getID()), 
)); 

:ORMを作成することを学ぶのに最適な方法ですが、もっと何かを探しているのならば真剣に、DoctrineやPropelの外観を与えることをお勧めします。

+0

確かに、私は主にこれを学ぶためにやっている。新しいMessage()を$ user - > messagesに格納するという奇妙な点に対処するために、私は本質的に、オブジェクトコンテキスト内からUser :: where()の動作を模倣する方法を模索していました。 '$ user - > messages = Messageのようなことをしています。 $ user - > messages :: find() 'は機能しません。オブジェクトの空のコピーを格納し、非静的メソッドを使用することは私が考えることができる最も近いものでした。しかし、あなたが言っていることは理にかなっています。私は、外来キーを明示的に渡すことなく、それらの間の関係を活用するより巧妙な方法があることを望みます。 –

+0

Messageオブジェクトを 'User :: addMessage()'に渡すことができ、その中にメッセージのid( '$ message-> getId()')をとり、必要なときにそのメッセージを格納します。 - DBからユーザーをフェッチすると、メッセージを自動的に取得(* eager loading *)したり、ユーザーが要求したときにメッセージを取得(*遅延ロード*)します。彼らが2度目に呼び出されたときにそれらを求めないようにしてください。 –

+0

ああ、これはかなりきれいな解決策のようだ。私は間違いなくあなたの応答のために、最高のソリューションを試してみるために、今夜これらのコンセプトを打ち明けているでしょう! –

0

を、どのできるクラスのメソッドを持つことは良い考えではありません静的コンテキストと非静的コンテキストの両方から呼び出すことができます。

アプリケーション全体でクラス/メソッドのアクセシビリティを実現するには、依存性注入、サービスコンテナ、および依存性注入指向プログラミングについて読んでおくとよいでしょう。

あなたのアプリケーションにDIを実装することで、あなたが言及したことの必要性がほとんどなくなるでしょう。

トラフのWebを調べることをお勧めします。作業中のコンテキストでの静的呼び出しは回避され、悪い習慣としてフラグが立てられます。オブジェクト指向プログラミングにおける静的/共有状態は、避けるべきである(シングルトンパターンと同様)。しかし、静的メソッドは目的や利点を持っていますが、Laravelのようなフレームワークでは「Facades」やEloquentのようないくつかのフレームワークが推奨されています。 。

関連する問題