Ist es ein Grundprinzip oder höchst wünschenswert, Klassenmethoden zu haben, die "$ this" anstelle eines Wertes zurückgeben?


8

Ich habe gerade erst angefangen, OOP zu lernen. Ich habe vor ungefähr einem Jahr angefangen und wahrscheinlich 15.000 Zeilen davon geschrieben. Aber ich habe alles mit kaum Erfahrung geschrieben, als ich mir die OOP anderer Leute angesehen habe.

Die meisten meiner Klassenfunktionen geben einen Wert zurück oder nehmen Änderungen an den Klasseneigenschaften vor und geben true / false zurück. Einige von denen, die einen Wert zurückgeben, speichern diesen Wert auch in einer Klasseneigenschaft (nachdem zuerst überprüft wurde, ob die Klasseneigenschaft bereits festgelegt ist, wodurch ein Datenbankaufruf vermieden werden kann).

Jetzt grabe ich viel in Magento / Zend und stelle fest, dass viele ihrer Klassenmethoden "$ this" zurückgeben. Soweit ich weiß, handeln Klassenmethoden, die $ this als Referenz und nicht als Wert zurückgeben, anders als bei regulären Funktionen, sodass Sie das gleiche Objekt zurückerhalten, mit dem Sie begonnen haben, und nicht eine Kopie.

Gibt $thisich etwas zurück, von dem ich viel mehr tun sollte? Erleichtert dies die Wartung und Verwendung des Codes? Ist eine Rückgabe $thiserforderlich, um Klassenmethoden zu verketten?


12
Dies ist eine Technik, mit der fließende Schnittstellen erstellt werden. Wenn ein fließendes Interface nicht Ihr Ziel ist, müssen Sie nicht zurückkehren $this. en.wikipedia.org/wiki/Fluent_interface
Robert Harvey

1
Vielleicht möchten Sie hier PHP angeben ...
Nathan C. Tresch

4
@ Robert, du solltest das zu einer Antwort machen.
Karl Bielefeldt

Hier ist ein Beispiel für eine fließende Schnittstelle in PHP ( devzone.zend.com/777/fluent-interfaces-in-php )
OnesimusUnbound

2
Sind verkettete Methoden notwendig? no();Sind sie manchmal sehr bequem? yes().yes().yes().yes().yes();: D
Viliam Búr

Antworten:


14

Dies ist eine Technik, mit der fließende Schnittstellen erstellt werden. Wenn ein Fluent Interface nicht Ihr Ziel ist, müssen Sie $ this nicht zurückgeben.

Mit fließenden Schnittstellen können Sie Code schreiben, der so aussieht (Pseudocode):

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

Dies funktioniert, da jeder Methodenaufruf aufgrund der Rückgabe des vorherigen Methodenaufrufs Zugriff auf das ursprüngliche Objekt hat this. Der obige Code entspricht mehr oder weniger:

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();
    ...
}

thiswird nicht immer zurückgegeben. Manchmal wird ein anderes Objekt zurückgegeben. Linq funktioniert so und gibt IEnumerablevon jeder Linq-Methode in der Kette eine (im Grunde genommen eine verzögerte Darstellung einer Sammlung, eine modifizierte Zustands-Engine) zurück.

Das Erstellen einer fließenden Schnittstelle erfordert mehr Aufwand und Voraussicht als das einfache Festlegen aller Parameter in einem Konstruktor. Sie müssen herausfinden, ob das Objekt über alles verfügt, was es benötigt, um voll funktionsfähig zu sein, und es ist nicht immer klar, was eine bestimmte Methode genau tut oder in welcher Reihenfolge Sie die Methoden aufrufen müssen. Zum Beispiel:

20.minutes.ago

sieht sauber aus, aber wie funktioniert es genau?

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


2

Wenn Sie $ zurückgeben, wird eine Instanz des Objekts zurückgegeben, zu dem die Methode gehört. Es gibt viele Fälle, in denen Sie dies tun möchten, aber bis Sie genau verstehen, was ich gerade gesagt habe, und einen Anwendungsfall dafür identifizieren können, brauchen Sie ihn nicht wirklich.

Beispiele für die Verwendung:

Ein btree ist ein Beispiel in PHP, in dem Sie ein Kind von $ this zurückgeben würden, was nicht genau dasselbe ist, aber ich denke, es hat Einfluss auf diese Diskussion.

Wenn Sie Ihren eigenen Konstruktor schreiben, geben Sie immer $ this zurück

Wenn Sie $ this zurückgeben, geben Sie zur Verdeutlichung von Referenzen einen Verweis auf das Objekt aus, zu dem die ausgeführte Methode gehört. Ich denke, die Regeln von PHP für den Betrieb einer Referenz im Vergleich zu einem Wert sind manchmal etwas unklar, aber in diesem Fall ist dies immer eine Referenz. Um es klar auszudrücken: Eine Referenz ist immer die Instanz, die Sie hatten, und niemals eine Kopie, während ein Wert eine Kopie ist. Dies sind zwei Arten von Argumentensemantik


Ich verstehe Returning $this returns an instance of the object that the method is a member of.Und in PHP OOP glaube ich, wie ich in meiner Frage gesagt habe und Sie in Ihrer Antwort sagen, dass die Instanz, die sie zurückgibt, tatsächlich dieselbe Instanz ist wie sie ... dh sie gibt keine Kopie von sich selbst zurück, sondern sich selbst. Wenn ich richtig verstehe.
Buttle Butkus

@ButtleButkus Ja, eine Referenz ist immer "die Instanz, die Sie hatten" und niemals eine Kopie, während ein "Wert" eine Kopie ist. Dies sind zwei Arten von Argumentensemantik.
Nathan C. Tresch

@ ButtleButkus Ich habe meine Antwort mit dieser Information geändert
Nathan C. Tresch

1

"Eine PHP-Referenz ist ein Alias, mit dem zwei verschiedene Variablen auf denselben Wert schreiben können. Ab PHP 5 enthält eine Objektvariable das Objekt selbst nicht mehr als Wert. Sie enthält nur eine Objektkennung, die Objektzugriffsberechtigten ermöglicht Finden Sie das tatsächliche Objekt. Wenn ein Objekt per Argument gesendet, zurückgegeben oder einer anderen Variablen zugewiesen wird, sind die verschiedenen Variablen keine Aliase: Sie enthalten eine Kopie des Bezeichners, der auf dasselbe Objekt verweist. "

Der eigentliche Vorteil der Rückgabe von $ liegt in den Entwurfsmustern für die Objektzusammensetzung, insbesondere in Magento. Nehmen Sie zum Beispiel Mage_Core_Sales_Order_Invoice-> capture (), das $ this zurückgibt. Diese Methode sieht aus wie:

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

die Linie:

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

Übergibt das Rechnungsmodell als Referenz, was bei Objektzusammensetzungsmustern sehr nützlich ist. Die Rückgabe von $ this ist ebenfalls eine Referenz. Daher kann die Methode, die -> capture () für ein Rechnungsmodell aufruft, mit einem verketteten Objektaufruf als Nächstes weiterarbeiten, um die Lesbarkeit des Kontextcodes zu gewährleisten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.