Ankündigung

Einklappen
Keine Ankündigung bisher.

Method-Chaining: We ermittelt man den erwarteten Typ eines Rückgabewertes?

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Method-Chaining: We ermittelt man den erwarteten Typ eines Rückgabewertes?

    Ich möchte verschiedene Methoden innerhalb meiner Klasse miteinander koppeln können:

    $o = new MyObject();
    $data = $o->read('*')->filter(array('name'=>'findme'))->sort('asc');

    Das erreiche ich durch Rückgabe einer Instanzreferenz:
    public function read($scope='') {
    ....
    return $this;
    }

    Jetzt ist aber meine Frage woher ich weiss wann die Kette zuende ist, denn die Zusammenschaltung soll variabel sein.
    Wie erkenne ich ob das Ziel für meinen Rückgabewert wieder eine andere Funktion ist und ich somit $this zurückgeben muss, oder ob ich einen String oder was auch immer liefern soll?

  • #2
    Eine Funktion sollte immer den selben Rückgabetyp haben. Eine Funktion, die einmal $this und einmal einen String zurück gibt, ist nach meinem Empfinden kaputt.

    Kommentar


    • #3
      Dann häng eine Methode dran, die das ganze "ausführt". Z.B. eine gernisches exec() oder etwas was zur Aufgabe passt.

      Kommentar


      • #4
        Der Typ des Rückgabewertes einer Methode hängt von der speziellen Aufgabe der Methode ab. Grob können die Methoden im Zusammenhang mit dem Method-Chaining in 3 Gruppen aufgeteilt werden:
        1. Methoden welche das Objekt erzeugen (__construct, create), Rückgabewert das Objekt.
        2. Methoden welche das Objekt manipulieren oder anders formuliert ein Verarbeitungsschritt durchführen, Returnwert das Objekt ($this)
        3. Methoden welche das Ergebnis in der gewünschten Form liefern (Rückgabe alle Typen außer das Obljekt selbst)
        Beim Method-Chaining bietet sich die folgende Schreibweise an welche eine Reihe von Vorteile aufweist. Beispiel:

        PHP-Code:
        $result tableArray::create($products)                      //objekt erstellen
          
        ->filter(function($row){return $row['quantity'] > 0;})     //verarbeitung 1
          
        ->innerJoinOn($categories,'cat','id','catId')              //verarbeitung 2
          
        ->orderBy('cat.name, quantity desc, name')
          ->
        fetchGroup(['catId'])                                    //Ergebnis liefern

        Das ist ein reales Beispiel. Ich weiß jetzt nicht phreund ob dein Beispiel #1 in die Richtung geht was du machen möchtest. Wenn ja, dann schau dir mal die Klasse TableArray an.

        Kommentar


        • #5
          es gibt auch noch methoden, welche ein anders object zurückgeben, welches mit dem ursprungsobject zusaxmmenhängt.
          wie auch immer - keien Code tags, irgendwie kein forgeschritten post.

          ich weiss auch nicht ob herumfiltern das optimale beispiel für methode chaining ist, aber um auf deine frgae zurückzukommen:
          Jetzt ist aber meine Frage woher ich weiss wann die Kette zuende ist,
          wenn du beispleilsweise mit render() eine ausgabe zurückgibst.

          Kommentar


          • #6
            Zitat von tomBuilder Beitrag anzeigen
            es gibt auch noch methoden, welche ein anders object zurückgeben, welches mit dem ursprungsobject zusaxmmenhängt.
            Ja. Und mit diesen neuen Objekt kann das Method-Chaining dann fortgesetzt werden. Man muss halt wissen was die Mehtode zurückgibt, wenn es ein Objekt ist welches es ist und welche Methoden man da dann "ranhängen" kann.
            Und dieser Fall ist gar nicht so selten.

            PHP-Code:
            $diffHour date_create('11:30')   //liefert DateTime-Objekt
              
            ->diff(date_create('tomorrow'))  //liefert ein DateInterval-Objekt
              
            ->format('%H')                   //liefert das Resultat

            Die format-Methode von DateInterval hat hier nichts mit der gleichnamigen Methode vom DateTime-Objekt zu tun!

            Wird eine Methode rangehängt welche das Objekt nicht kennt dann quittiert und PHP das mit einem "Fatal error: Uncaught Error: Call to undefined method ..". Lange Ketten mit dem Method-Chaining können das Debuggen erschweren.
            Daher der Tipp mit der Schreibweise #4. Dort können leicht einzelne Zeilen auskommentiert werden und das Resultat z.B. mit var_dump() ausgegeben werden um zu schauen was da los ist.




            Kommentar


            • #7
              Zitat von jspit Beitrag anzeigen
              1. Methoden welche das Objekt erzeugen (__construct, create), Rückgabewert das Objekt.
              2. Methoden welche das Objekt manipulieren oder anders formuliert ein Verarbeitungsschritt durchführen, Returnwert das Objekt ($this)
              3. Methoden welche das Ergebnis in der gewünschten Form liefern (Rückgabe alle Typen außer das Obljekt selbst)
              Vielen Dank, dieses Modell gefällt mir sehr gut und beantwortet auch meine Frage, zumindest in der Theorie
              Ich habe z.B. eine Klasse die Daten in einem bestimmten Dateiformat verarbeitet (CSV). Ich kann damit solche Daten einlesen aber auch erstellen und abspeichern. Würde das dann so umsetzen:

              PHP-Code:
              $o = new Csv();

              $o->load($infile); # creator function, returns $this
              $o->load($infile)->row(5)->delete();

              $o->reset(); # creator function, returns $this
              $o->add(array('dcol1','dcol2','dcol3')); # data manipulators, always returns $this
              $o->row(10)->col(2)->replace('^d''data'); # data manipulators, always returns $this

              $o->toString(); # terminal function, returns data array as string
              $o->save($outfile); # terminal function, returns true or false 

              Kommentar


              • #8
                wie schon von jspit erwähnt
                PHP-Code:
                $o->add(array('dcol1','dcol2','dcol3')); # data manipulators, always returns $this 
                eben icht, wenn das add nicht ausgeführt werden kann.
                PHP-Code:
                $o->row(10)->col(2)->replace('^d''data'); # data manipulators, always returns $this 
                auch fraglich, und schein, wenn der entwickler weiss was in 10/5 steht ..

                PHP-Code:
                $o->toString(); 
                kann man als argument fwrite übergeben, das load infile und save outfile macnht mE. keiennsehr grossen mehrwert.
                PHP-Code:
                $o->save($outfile); # terminal function, returns true or false 
                true/false ist super um rauszufinden was für ein fehler wirklich aufgegtreten ist.
                finde das eher unpraktisch so zum arbeiten.

                Kommentar


                • #9
                  Je nach Anwendungszweck macht es auch Sinn eine neue Objekt-Instanz zurückzugeben anstatt $this.

                  Ich setzte neu auch vermehrt auf diesen Ansatz.

                  Siehe Beschreibung z.B https://laravel.com/docs/8.x/collect...ilable-methods

                  Kommentar


                  • #10
                    Zitat von tomBuilder Beitrag anzeigen
                    wie schon von jspit erwähnt
                    PHP-Code:
                    $o->add(array('dcol1','dcol2','dcol3')); # data manipulators, always returns $this 
                    eben icht, wenn das add nicht ausgeführt werden kann.
                    Dafür gibts Exceptions. Wenn ich dich richtig verstehen, bemägelst du weiter unten selbst true/false als "Fehlerbehandlung".

                    Was mir bei den Interface auffällt ist eher. "->row(10)->col(2)" damit wird der state des Objekts manipuliert, ohne das es wirklich ersichtlich ist.

                    PHP-Code:
                    $o->row(9)->replace('^d''data');
                    $o->row(10)->col(2)->replace('^d''data');
                    $o->row(11)->replace('^d''data'); 
                    Die letzte Zeile würde etwas anderes machen als erwartet, weil col noch auf 2 steht. row() und col() sollten meiner Meinung nach auf keinen Fall das Objekt selbst zurückgeben. Ggf. ein Objekt was Datenbereiche auf das eigentliche Objekt referenziert.

                    Zitat von strub Beitrag anzeigen
                    Je nach Anwendungszweck macht es auch Sinn eine neue Objekt-Instanz zurückzugeben anstatt $this.
                    Das ist die Entscheidung ob das Objekt mutable oder immutable sein soll. Teilweise ist das gar nicht so leicht zu entscheiden.

                    Kommentar


                    • #11
                      phreund : Mir stellt sich da noch die Frage welche Aufgabe genau deine Klasse lösen soll. CSV-Dateien bearbeiten?

                      CSV-Dateien werden üblicherweise in ein Array eingelesen. Das Einlesen in ein Array ist mit dem SplFileObject in 2-3 Zeilen erledigt. Dazu gibt es einige Threads hier im Forum. Habe mal dies hier CSV-Datei in ein zweidimensionales Array einlesen als Beisiel rausgesucht. Das weitere läuft dann auf Array-Manipulationen hinaus.

                      Kommentar


                      • #12
                        Stimmt erc exceptioins, finde ich aber in ewiglangen ketten nur schwer zu debuggen.
                        das mit dem state, hab ich völlig übersehen.

                        und ja jspit das mit der aufgabe der klasse ist mir auch nicht klar.
                        fände ich wichtig zu überlegen, bevor man sich über methode chaining gedanken macht.

                        und hier ist nichts forgeschritten

                        Kommentar


                        • #13
                          Zitat von tomBuilder Beitrag anzeigen
                          Stimmt erc exceptioins, finde ich aber in ewiglangen ketten nur schwer zu debuggen.
                          Ewig lange Ketten mit Method-Chaining sind mitunter schwer zu debuggen. Exceptions mit aussagekräftigen Mitteilungen zu werfen sind nach meiner Meinung aber genau das Mittel die Fehlersuche hier zu vereinfachen wenn es an einer Stelle der Kette nicht weitergeht. In Verbindung mit der oben #4 vorgeschlagenen Schreibweise habe ich noch zusätzliche Hinweise zu zum Fehler aufgrund der Zeilennummer.

                          Kommentar

                          Lädt...
                          X