値ではなく「$ this」を返すクラスメソッドを持つことは、基本的な原則ですか、それとも非常に望ましいですか?


8

私は本当にOOPを学び始めたばかりです。私は約1年前に開始し、おそらく15,000行を書きました。しかし、他の人のOOPを見た経験はほとんどありませんでした。

ほとんどのクラス関数は値を返すか、クラスのプロパティを変更してtrue / falseを返します。値を返すものの一部は、その値をクラスプロパティに保存します(クラスプロパティが既に設定されているかどうかを最初に確認した後、データベースの呼び出しを回避できます)。

今私はMagento / Zendで多くの掘り下げを行っており、それらのクラスメソッドの多くが "$ this"を返すことに気づきました。私が理解しているように、通常の関数とは異なり、$ thisを返すクラスメソッドは値ではなく参照によって動作するため、コピーではなく、最初に開始したのと同じオブジェクトを取得できます。

$thisもっとやりたいことを返すのですか?コードの保守と使用が容易になりますか?$thisクラスメソッドをチェーンするために戻り値は必要ですか?


12
これは、流暢なインターフェイスを作成するために使用される手法です。 Fluent Interfaceが目的でない場合は、戻る必要はありません$thisen.wikipedia.org/wiki/Fluent_interface
Robert Harvey

1
ここでPHPを指定することをお勧めします...
Nathan C. Tresch 2013年

4
@ロバート、あなたはそれを答えにするべきだ。
カールビーレフェルト2013年

ここでPHP(で流れるようなインターフェイスのサンプルのdevzone.zend.com/777/fluent-interfaces-in-phpが
OnesimusUnbound

2
連鎖メソッドは必要ですか?no();彼らは時々とても便利ですか?yes().yes().yes().yes().yes();:D
ViliamBúr2013

回答:


14

これは、流暢なインターフェイスを作成するために使用される手法です。Fluentインターフェイスが目的でない場合は、$ thisを返す必要はありません。

Fluentインターフェイスを使用すると、次のようなコード(疑似コード)を記述できます。

private void makeFluent(Customer customer) {
    customer.newOrder()
            .with(6, "TAL")
            .with(5, "HPK").skippable()
            .with(3, "LGV")
            .priorityRush();
}

前のメソッド呼び出しがを返すため、各メソッド呼び出しは元のオブジェクトにアクセスできるため、この方法は機能しますthis。上記のコードは、ほぼ以下と同等です。

private void makeFluent(Customer customer) {
    var newOrder = customer.newOrder()
    newOrder.with(6, "TAL");
    newOrder.with(5, "HPK", skippable := true);
    newOrder.with(3, "LGV");
    newOrder.priorityRush();
    ...
}

this常に返されるわけではありません。別のオブジェクトが返される場合があります。Linqはこのように機能IEnumerableし、チェーン内の各Linqメソッドから(基本的にはコレクションの遅延表現、変更された状態エンジン)を返します。

流暢なインターフェイスを作成するには、コンストラクターですべてのパラメーターを単に設定するよりも、より多くの労力と先見性が必要です。オブジェクトが完全に機能するために必要なすべてを備えているかどうかを判断する必要があります。また、特定のメソッドが何を実行するか、またはメソッドを呼び出す必要がある順序が常に明確であるとは限りません。例えば:

20.minutes.ago

見た目はきれいですが、どのように機能しますか?

http://en.wikipedia.org/wiki/Fluent_interface
http://www.martinfowler.com/bliki/FluentInterface.html


2

$ thisを返すと、メソッドがメンバーであるオブジェクトのインスタンスが返されます。これを実行したいケースはたくさんありますが、今言ったことが何を意味するのかを正確に理解し、そのユースケースを特定できるようになるまでは、実際には必要ありません。

これを使用するタイミングの例:

btreeは、PHPで$ thisの子を返す例です。これはまったく同じではありませんが、この議論に関係していると思います。

独自のコンストラクタを作成すると、常に$ thisが返されます

参照について明確にするために、$ thisを返すと、実行中のメソッドが含まれているオブジェクトへの参照が渡されます。参照と値を比較するときのPHPのルールは、ときどき不明確になると思いますが、この場合、$ thisは常に参照です。明確にするために:参照は常に「あなたが持っていたインスタンス」であり、コピーではありませんが、「値」はコピーです。これらは2つのタイプの引数セマンティクスです


私が理解していることReturning $this returns an instance of the object that the method is a member of.と、PHP OOPでは、私の質問で言ったように、あなたの回答で言っているように、返されるインスタンスは実際にはまったく同じインスタンスです...つまり、それ自体のコピーではなく、それ自体を返します。私が正しく理解しているなら。
Buttle Butkus、2013年

@ButtleButkusはい、参照は常に「あなたが持っていたインスタンス」であり、決してコピーではありませんが、「値」はコピーです。これらは、2つのタイプの引数セマンティクスです。
Nathan C. Tresch 2013年

@ButtleButkus私はその情報で私の回答を修正しました
Nathan C.

1

「PHPリファレンスはエイリアスです。これにより、2つの異なる変数が同じ値に書き込むことができます。PHP5以降、オブジェクト変数にはオブジェクト自体が値として含まれなくなりました。オブジェクトアクセサーにアクセスを許可するオブジェクト識別子のみが含まれます実際のオブジェクトを見つけます。オブジェクトが引数で送信されたり、返されたり、別の変数に割り当てられたりする場合、異なる変数はエイリアスではなく、同じオブジェクトを指す識別子のコピーを保持します。」

$ thisを返す本当の利点は、オブジェクト構成のデザインパターン、特にMagentoにあります。たとえば、$ thisを返すMage_Core_Sales_Order_Invoice-> capture()を考えてみます。このメソッドは次のようになります。

  public function capture()
    {
        $this->getOrder()->getPayment()->capture($this);
        if ($this->getIsPaid()) {
            $this->pay();
        }
        return $this;
    }

この線:

$this->getOrder()->getPayment()->capture($this);

請求書モデルを参照として渡します。これは、オブジェクト構成パターンで非常に役立ちます。$ thisの戻り値も参照です。したがって、請求書モデルで-> capture()を呼び出すメソッドは、コンテキストコードを読みやすくするために、次にチェーンされたオブジェクト呼び出しを引き続き処理できます。

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