5

私は単純な ORM ソリューションに取り組んでおり、トリッキーな状況に遭遇しました。理想的には、メソッドの呼び出し方法に応じて、静的コンテキストとオブジェクト コンテキストの両方でメソッドを使用できるようにしたいと考えています。これが可能かどうかはわかりませんが、私が言いたいことは次のとおりです。

User モデルが where() を静的に呼び出したいとします。これは現在正常に動作します。たとえば、次のようになります。

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

現在、関係もサポートしています。たとえば、ユーザーはメッセージを持つことができます。この関係が確立されたら、メッセージ モデルの空のコピーをユーザー モデルに格納し、外部キーを設定するだけです。例えば:

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

さて、理想的には、次のように呼び出したいと思います:

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

非静的コンテキストでは、外部キーがユーザーの ID と一致するメッセージのみをプルするために、このコンテキストでは $this ->foreign_key を使用します。このタイプのコンテキスト切り替えは PHP で可能ですか? 静的コンテキストから $this を参照すると、静的メソッドとしてエラーがスローされ、$this に依存するべきではありません (明らかな理由から、静的コンテキストから呼び出された場合、$this は存在しません)。

これを回避する賢い方法はありますか?static キーワードの有無にかかわらず、2 つの異なるプロトタイプを持つようにメソッドをオーバーロードしようとしましたが、これにより再宣言エラーがスローされました。

4

4 に答える 4

5

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

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

私はおそらくこれをあまりよく説明していません、ただこのコードを見てください:

<?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);
于 2012-06-26T21:54:46.977 に答える
4

あなたの質問に答えていないことをお詫びします、しかし私は...コメントに合わないいくつかのコメントがあります。あなたがしていることは少し非論理的です。

$user->messages = new Message();

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

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

ここでは、ユーザーメッセージからSELECTしようとしていますが、それは意味がありません。
あなたがすべきことは、Userクラスで行ったのと同じです。メッセージを静的に取得してから、ユーザーに割り当てます。

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

特定の主キーを持つメッセージを検索する必要がある場合は、それをパラメーターとしてwhereメソッドに渡します。これを拡張して、多くの句を使用できます。

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

また、個人的なメモを追加したいと思います。ORMを作成することは学ぶのに最適な方法ですが、もっと深刻なものを探している場合は、DoctrineまたはPropelを見てみることをお勧めします。

于 2012-06-26T21:36:40.637 に答える
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 の 19 行目の
Static で静的に呼び出されるべきではありません。

メソッドを静的として宣言すると、どの方法で呼び出されても静的になります。

したがって、答えは「はい」だと思います。この回避策を使用して実行できますが、お勧めしません。両方の方法が必要な場合は、 と の 2 つのメソッドを追加することをお勧めしpublic function find()ますpublic static function findStatic()

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

于 2012-06-26T21:27:45.487 に答える
0

理論的および実用的な観点から、静的コンテキストと非静的コンテキストの両方から呼び出すことができるクラス メソッドを持つことはお勧めできません。

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

アプリケーションに DI を実装することにより、おそらく、あなたが言及したことの必要性を失うでしょう。

ウェブで調査することをお勧めします。作業中のコンテキストでの静的呼び出しが回避され、悪い習慣としてフラグが立てられることがわかります。オブジェクト指向プログラミングにおける静的/共有状態は、(シングルトン パターンと同様に) 避けるべきものです。

誤解しないでください->静的メソッドには目的と利点がありますが、それを使用する方法は時代遅れです(Laravelなどの一部のフレームワークはこの悪い慣行を促進していますが、「Facades」やEloquentなど)。

于 2014-06-23T08:14:03.993 に答える