Ankündigung

Einklappen
Keine Ankündigung bisher.

Namensschema für Methoden einer Klasse ("Best Practise")

Einklappen

Neue Werbung 2019

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

  • Namensschema für Methoden einer Klasse ("Best Practise")

    Es geht in erste Linie um Konsistenz und Einfachheit.

    Ich persönlich merke dass ich im Quellcode manchmal inkonsistent meine Namen vergebe und möchte dies nun ändern.

    Dafür muss man ein gemeinsames Beispiel haben um aktiv daran arbeiten zu können.

    Nehmen wir an wir haben eine Klasse mit dem Namen "Wetter".

    Nehmen wir an die Datenbank sieht wie folgt aus:
    PHP-Code:
    ID Stadt Jetziges_Wetter 
    Für diese Klassen möchten wir nun Methoden schreiben die folgendes können sollen (Stichwörter am Ende sind zur Markierung extra so verfasst):

    1.) Neunen Eintrag anlegen (Insert)
    2.) a.) Einzelne Column ändern Jetziges_Wetter (update)
    2.) b.) Einzelne Column ändern Stadt (update)
    3.) a.) Gesamte Row auswählen an Hand ID (select)
    3.) b.) Gesamte Row auswählen an Hand Stadt (select)
    4.) a.) Einzelne Column Jetziges_Wetter auslesen an Hand ID (select)
    4.) b.) Einzelne Columns Jetziges_Wetter auslesen an Hand der Stadt (select)
    5.) Einzelne klasseninterne Variable setzen (z.B. $_var)
    6.) Einzelne Klasseninterne Variable auslesen (z.B. $_var)
    Nun frage ich euch:
    1.) Ist es überhaupt sinnvoll solch ein Schema zu haben ?
    Denn einzelne Columns(Punkt 4.)) könnten z.B. auch per Row (3.) auslesen.
    Somit würde man sich Schreibarbeit sparen, ist dieses "sparen" jedoch gut oder spart man am falschen Ende ?

    2.) Wie würdet Ihr diese Methoden nennen ?
    Es ist gang und gebe mit getter/setter zu arbeiten.
    Ich komme aber leicht durcheinander wenn ich interne Variablen setze und etwas in die Datenbank speicher, da ich schnell inkonsistent benenne.

    Hier meine Lösung zur oben genannter Aufgabenstellung:
    1.) setRow($Stadt = '', $Jetziges_Wetter = '')
    2.) a.) setColumnJetziges_Wetter ($ID)
    2.) b.) setColumnStadt ($ID)
    3.) a.) getRowById ($ID)
    3.) b.) getRowByStadt ($Stadt)
    4.) a.) getColumnJetziges_Wetter($ID)
    4.) b.) getColumnJetziges_Wetter($Stadt)
    5.) setVar ($var)
    6.) getVar ($var)
    3.)
    Da ich in der Datenbank die Werte mit einem Underscore trenne, kommt alleine schon eine inkonsistenz bei dem Namen 2.)a.) zu stande, oder nicht ?
    Sollte daher auch die Datenbank dem Quellcode angepasst werden oder ist der Methodenname einfach nur dämlich?


    4.)
    3.)a.) und 3.)b.) sind auch irgendwie "komisch" benannt, oder würdet ihr diese getter ähnlich nennen ?

    Ich glaube die einfachste Frage ist, wenn Ihr solch einen Quellcode vor euch hättet, wie hättet ihr diesen am liebsten benannt dass ihr euch sofort reinfindet ?

    Meine Absicht ist es möglichst "perfekten" Code zu schreiben, im Sinne von Konsistenz und "Durchschaubarkeit".

    Wenn nikosch, tr0y oder ein anderer erfahrener PHP´ler mein Script anschaut soll er binnen kürzester Zeit wissen was Sache ist.

    Vielen Dank für jeglichen Input.

    Vor allem von erfahrenen Usern, die bestimmt desöfteren schon Probleme damit hatten und hier hoffentlich ihr Wissen preis geben.


  • #2
    Ich habe den Eindruck, Du verwürfelst hier Businesslogik (Domäne, Model) und Datenbankabstraktion/-zugriff. Ein Model wird nichts über seine Existenz (Herkunft) wissen, von daher kennt es auch kein getRow o.ä.
    --

    „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
    Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


    --

    Kommentar


    • #3
      Um die Frage zu beantworten: es gibt kein allgemeingültiges Schema. Die Frage ist doch: "Was möchtest du mit der Klasse modellieren?"

      Deinen Ausführungen zufolge soll die Klasse "Wetter" ein DTO oder Domönen-Objekt sein, wobei letzteres nicht ganz zutreffen wird, da die Methoden eher den Anschein eines TableDataGateway-DTOs machen.

      From the scratch: wenn du das Wetter in verschiedenen Städten modellieren möchtest, musst du dich fragen, welche Elemente du für eine Aussage wie "Das Wetter in Berlin ist schön." benötigst. Das wird ein Wetter-Objekt, eine Stadt und eine Beziehung zwischen beiden sein. Interessierst du dich für einfache Neuigkeiten (News), so reicht sicher ein einzelnes Objekt. Sofern wir über ein TableDataGateway sprechen, würde ich mit "Wetter" ein DTO erwarten, das seinen Zustand (schön, regnerisch, ...) und seine Stadt auf Anfreuge preis gibt:

      PHP-Code:
      class Weather {
         public function 
      getCity(){ ... }
         public function 
      getState(){ ... }

      Um es in der Datenbank zu speichern oder in der GUI zu addressieren, kann es auch eine Id haben:

      PHP-Code:
      class Weather {
         public function 
      getId(){ ... }
         public function 
      getCity(){ ... }
         public function 
      getState(){ ... }

      Sofern du ein solches erzeugen und speichern möchtest, sollten entsprechende Konstruktor-Argumente oder setter vorhanden sein.

      Das alles ist jedoch nur dann sinnvoll, wenn du noch einen Mapper besitzt, der das DTO in die Datenbank schreiben oder von dort lesen kann. Sofern du ein Domänen-Objekt implementieren möchtst, kann dieses noch einige Methoden wie load() und save() besitzten.

      Du siehst also: die Frage ist nicht so einfach mit 1a) oder 2b) zu beantworten, sondern ist abhängig vom Kontext und dem WAS du entwerfen/modellieren möchtest.
      Viele Grüße,
      Dr.E.

      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      1. Think about software design before you start to write code!
      2. Discuss and review it together with experts!
      3. Choose good tools (-> Adventure PHP Framework (APF))!
      4. Write clean and reusable software only!
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

      Kommentar


      • #4
        Uiuiui, dann muss ich wohl eine Etage tiefer anfangen.

        @nikosch
        Dies kann durchaus sein.

        Zitat von dr.e. Beitrag anzeigen
        Deinen Ausführungen zufolge soll die Klasse "Wetter" ein DTO oder Domönen-Objekt sein, wobei letzteres nicht ganz zutreffen wird, da die Methoden eher den Anschein eines TableDataGateway-DTOs machen.
        [...]
        Das alles ist jedoch nur dann sinnvoll, wenn du noch einen Mapper besitzt, der das DTO in die Datenbank schreiben oder von dort lesen kann. [...]
        Vorweg:
        Das Thema ORM ist das einzige Tutorial, welches ich mir bei der Zend_Tutorialreihe aus Zeitgründen (Über 2 Std, was einer Bearbeitungszeit von ~ 1 Tag gleich kommt) bisher nicht angeschaut habe.

        Ich hatte mir mal Doctrine beiläufig als ORM angeschaut, jedoch dachte ich, dass ich dies nicht benötige.

        Was ich gefunden haben :
        http://media.adventure-php-framework...em_diagram.png

        sowie die eine einfache Beispielmapperdatei mit "load" als Prefix:

        http://rabbitphp.org/pages/domain-ob...object-example

        Demnach hat der Mapper keine normalen getter und setter.

        Wo dr.e. richtig lag ist, dass es sich um ein TableData Gateway handelt (TableDB Class von Zend).
        Ist es denn wirklich falsch bzw. jenseits von "sauber" programmier, wenn ich der Zend_DBTable Class Methoden gebe welche die Daten in der Datenbank manipulieren bzw. getten/setten und diese dann direkt im Controller weiterverarbeite ?


        Aus dr.e. Beispiel entnehme ich, dass Getter und Setter im TableDataGateway durchaus möglich sind.

        Desweiterem entnehme ich dem Post, dass es keinen Bedarf gibt die gesamte Row ausgeben zu lassen als Array sondern - sofern mehrere Daten benötigt werden - die einzelnen Columns durch die Getter/Setter Methoden zusammengeschustert werden.
        Ist dies korrekt ?

        Die einzige Außnahme bildet natürlich das Update, welches als "save" betitelt werden darf.

        Also würde dies so aussehen:

        PHP-Code:
        1.save($Stadt ''$Jetziges_Wetter '')
        2.a.) saveJetziges_Wetter ($ID)
        2.b.) saveStadt ($ID)
        4.a.) loadJetziges_Wetter($ID)
        4.b.) loadJetziges_Wetter($Stadt)
        5.setVar ($var)
        6.getVar ($var
        Soweit korrekt oder lohnt es sich zeitnah tiefer in die ORM Geschichte einzusteigen zwecks starker Notwendigkeit ?

        Kommentar


        • #5
          Für mich würde sich eine Wetteranwendung in etwa so darstellen (nagel mich jetzt nicht auf die Begriffe fest, da hat der Doc durchaus mehr Softwaredesign inhaliert):

          Der Benutzer (Client) stellt eine Anfrage an einen Manager. Z.B. gib mir das Deutschlandwetter, gib mir 7-Tage-Wetter für Postleitzahl xyz usw. Das Nutzerinterface abstrahiert also der Manager.
          Der Manager verwaltet verschiedene Wetterobjekte. Je nachdem was die App bietet können das allgemeine und spezialisierte Objekte sein (allgemein: Deutschlandwetter, interpolierte Wetterdaten, speziell: Wetter(meß)daten für ein spezifisches PLZGebiet). Jedenfalls „guckt“ der Manager, ob er ein bestimmtes angefordertes Wetterobjekt in seinem Portfolio hat. In PHP wird das eher selten der Fall sein, in länger laufenden Apps (wie vielleicht auch Javascript) sammelt er über die Ausführungszeit eben angeforderte Objekte. Wenn ja mappt er eine Anforderung auf das bestehende Objekt, liefert es also aus. Auf das Wetterobjekt können dann die Abfragen der einzelnen Daten erfolgen. Hier haben wir die zweite Schnittstelle - getAverageTemperature () oder ähnliches.
          verfügt der Manager nicht über ein passendes Wetterobjekt lädt er es aus der Datenschicht. Genauer: Er lässt es laden bzw. erzeugen. Dabei könnten potentiell z.B. einen Datenabstraktionsschicht und eine Factory beteiligt sein. Warum ich das sinnvoll halte, lass mich an einem Beispiel erklären:
          Nehmen wir mal an, Du hättest eine Datenbank mit Gebiets- und Geodaten, um die Anfragen verwalten zu können. Die Datenbank speichert auch Zugangsdaten zu lokalen Wettermeßstationen in den einzelnen Städten. Die eigentlichen Meßdaten liefert dann vielleicht eine XML-Schnittstelle zu einem Service, den ein städtisches Wetteramt betreibt. Schon hast Du keine reine Datenbankabfrage mehr, auf die sich Dein Model stützt, sondern Du musst nach bestimmten Verfahren Geodaten auslesen, um über die Postleitzahl die Wetterstationenn zu ermitteln und dann über eine XML-Schnittstelle konkrete lokale Daten abfragen. Vielleicht will man dann noch einen Cache für die Daten benutzen. Jedenfalls alles gute Gründe, das Datenhandling separat abzuhandeln. Die gesamte Kommunikation mit beteiligten Datenschichten wie Datenbank, XML-Files, ferne Ressourcen und APIs bildet dann die dritte Schnittstelle. Diejenige, die Deinen vorgeschlagenen Methodenbezeichnern im Ausgangsthread vermutlich am nächsten kommt.
          Umgekehrt funktioniert das dann genauso. Wird im Backend ein Wetterobjekt erstellt (natürlich eher ein Datenobjekt, als ein view-spezifisches), weist Du den Manager zum Schluß an, alle verwalteten Objekte mit der Datenbank zu synchronisieren - neue erfahren ein Insert, existierende falls nötig ein Update. Mit etwas Gehirnschmalz kann man hier sogar Datenbankoperationen zusammenfassen und muss nicht jedes Objekt einzeln verarbeiten.

          Das mal so als Idee, wie eine Trennung in beteiligte Akteure motiviert sein kann.

          ORM ist irgendwo schon wieder ein sehr spezielles Prinzip, was nicht generell auf die Problemstellung passen muss und m.E. auch nur einen Teil der Frage beantwortet.
          --

          „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
          Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


          --

          Kommentar


          • #6
            save($Stadt = '', $Jetziges_Wetter = '')
            Das halte ich (persönlich) für ungünstig. In anderen Sprachen gibt es zwar überladene Funktionen, aber für diese Eigenschaften hier würde ich das nicht verwenden. Das wird später eh überflüssig, wenn Du 20 Eigenschaften hast und immer andere füllen bzw. leer lassen willst. Dann lieber über Setter und Getter.

            Absolutes No Go ist die Vermischung von Deutsch und Englisch.

            Ich würde insofern auf bereits existierende ORMs setzen, als dass diese bereits jede Menge Funktionalität implementiert haben und Du i. d. R. nur eine Konfiguration und/oder "Model-Klassen" schreiben musst, was Dir jede Menge Arbeit abnimmt.

            4.) a.) loadJetziges_Wetter($ID)
            4.) b.) loadJetziges_Wetter($Stadt)
            Anhand von was willst Du unterscheiden, was da übergeben wurde?

            Irgendwie sieht das alles recht krude aus...

            Kommentar


            • #7
              Wenn du schon Bei Zend_* warst, warum hast du dir nicht die Beispiele aus dem Quickstart angesehen? Dort gibt es drei Klassen für eine Datenbanktabelle (oder etwas anderes):
              - ein Model, welches stupide die Daten hält und diese ins richtige Format bringt
              - ein Mapper, welcher Daten aus einem Gateway abholt und diese in Models speichert
              - bei Zend_Db eine Zend_Db_Table_Abstract-Instanz, welches als Gateway zur Datenbank fungiert, oder ein Gateway zu einer Datei, Service (wobei man hier überlegen müsste, ob ein Service-Layer nicht gleich besser wäre) usw.

              Kommentar


              • #8
                Anhand von was willst Du unterscheiden, was da übergeben wurde?
                Anhand des Objekttyps natürlich
                --

                „Emoticons machen einen Beitrag etwas freundlicher. Deine wirken zwar fachlich richtig sein, aber meist ziemlich uninteressant.
                Wenn man nur Text sieht, haben viele junge Entwickler keine interesse, diese stumpfen Texte zu lesen.“


                --

                Kommentar


                • #9
                  Anhand des Objekttyps natürlich
                  Das klingt ja sehr generisch..

                  Kommentar


                  • #10
                    Ich muss gleich zum Zug, darum nur kurz eine Frage: warum versteifst du dich so auf das TDG-Pattern? Überlege doch zunächst auf Business-Architektur-Ebene, welche Objekte im Spiel sind und welche Bedeutung diesen zukommt.
                    Viele Grüße,
                    Dr.E.

                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                    1. Think about software design before you start to write code!
                    2. Discuss and review it together with experts!
                    3. Choose good tools (-> Adventure PHP Framework (APF))!
                    4. Write clean and reusable software only!
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                    Kommentar


                    • #11
                      Es hätte wenig Sinn gemacht, mit meinem alten Wissensstand hier weiter herumzudümpeln.

                      Daher schreibe ich nun ~2 Wochen später,
                      nachdem ich dazu kam das Zend Quickstart Tutorial sowie das letztes Tutorial einer "Zend Tutorial Reihe" zu Mappern anzuschauen & durchzuarbeiten.
                      __________________________________

                      Zitat von dr.e. Beitrag anzeigen
                      Ich muss gleich zum Zug, darum nur kurz eine Frage: warum versteifst du dich so auf das TDG-Pattern? Überlege doch zunächst auf Business-Architektur-Ebene, welche Objekte im Spiel sind und welche Bedeutung diesen zukommt.
                      Simpel:
                      Mir war vorher bei Zend kein anderes Pattern bekannt.

                      Während der Lehrstunden sind mir jedoch Unterschiede zu den Tutorial aufgefallen bzw. z.T. Unstimmigkeiten.

                      __________________________________

                      Grundannahme:
                      Da es ein beliebtes Beispiel ist, nehmen wir das Beispiel "Gästebuch".
                      In diesem kleinen Beispiel geht es nur darum alles auf einer Seite anzeigen zu lassen.
                      Als Pattern nehmen wir aus unserem Werkzeugkasten das DataMapper Pattern.

                      Version 1.)
                      Zend Framework Quickstart


                      Als allererstes macht das Quickstart die Aussage, dass "save", "find" und "fetchAll" quasi Default Methoden in einem Mapper sind.

                      A typical API for a data mapper is as follows:
                      PHP-Code:
                      class Application_Model_GuestbookMapper
                      {
                          public function 
                      save($model);
                          public function 
                      find($id$model);
                          public function 
                      fetchAll();

                      Quelle:http://framework.zend.com/manual/en/...ate-model.html

                      Ist das richtig und wenn nein/ja, trifft es für alle Fälle zu ?

                      Vereinfachter Aufbau der Applikation:
                      /models/DbTable/Guestbook.php
                      /models/Guestbook.php
                      /models/GuestbookMapper.php
                      /controllers/GuestbookController.php

                      Wie fetchAll funktioniert:
                      Controller ruft neue Instanz des Mappers auf,
                      Controller übergibt an das View Objekt: Mapper->fetchAll
                      Mapper ruft interne getDbTable() Methode auf und greift somit durch eine Instanz von Zend_DbTable_Abstract (/DbTable/Guestbook.php) per fetchAll auf die DB zu.
                      Mapper erstellt per foreach() für jede Row ein eigenes Guestbook Obj. (/models/Guestbook.php), sammelt diese in einem Array und gibt dies letzendlich zurück.

                      Version 2.)
                      Video Tutorial (Siehe oben)


                      Vereinfachter Aufbau der Applikation:
                      /models/DomainAbstract.php
                      /models/DataMapperAbstract.php

                      /models/Guestbook.php
                      /models/GuestbookMapper.php
                      /models/GuestbookController.php

                      Wie fetchAll() funktioniert:
                      Controller ruft per getInstance() Methode eine Instanz von GuestbookMapper auf.
                      [Unterschied, bei Zend war es lediglich durch "new", hier wird es durch ein Singleton Pattern aufgerufen]
                      Controller übergibt an das View Objekt: Mapper->fetchAll
                      Mapper ruft $this->getDb Methode auf, welche zur Parentclass DataMapperAbstract führt und dort durch Zend_Db_Table::getDefaultAdapter() die derzeitige Verbindung holt.
                      Mapper baut die Query zusammen (->select()->from(tablename)) und führt danach auch die query durch ->fetchAll aus
                      [Unterschied, bei Zend wird nicht from() verwendet sondern durch die Instanz von Zend_DbTable_Abstract weiß die Applikation bereits die Tabelle]
                      Mapper erstellt per foreach() für jede Row ein eigenes Guestbook Obj. (/models/Guestbook.php), sammelt diese in einem Array und gibt sie letzendlich aus.

                      Weiterer Unterschied zum Zend Beispiel:
                      Das Model Guestbook.php ist ein Kind von DomainAbstract.php.
                      DomainAbstract hat als Property die $_id und die Methoden setId und getId.
                      Dies ist dafür gedacht nochmals ein wenig Tipparbeit zu sparen da man viele Klassen um diese erweitern kann
                      (So gut wie alles hat eine eindeutige Id um festzustellen ob ein update oder insert erfolgt)

                      Bei Zend gab es keine solche Abstract Class sondern die Property "Id" wurde direkt in das Objekt geschrieben.

                      Version 3.)
                      Google


                      Google sagt man sollte auf nicht benutzte Getter und Setter verzichten, der Performance wegen.
                      Meine Interpretation nach sollten somit auch "naive" (default) getter/setter vermieden werden.
                      [Siehe Zend]

                      Avoid writing naive setters and getters
                      Quelle:
                      http://code.google.com/intl/de-DE/sp...izing-php.html
                      __________________________________

                      Es ist schwer alles einigermaßen sauben zusammen zu bekommen, damit man es zumindest auf dem zweiten Blick erkennt.

                      Meine persönliche Einschätzung ist, dass beide Wege Vorteile haben die am besten sind.

                      Bei Zend Quickstart scheint es sauberer gelöst zu sein mit dem Zend_DbTable_Abstract, so dass der Mapper nicht von DataMapperAbstract per getDb den DefaultAdapter holen muss und dann extra eine "from()" Query erzeugt.
                      Allerdings wurde im VideoTutorial auch etwas gesagt dass DataMapperAbstract die interne Property $_db als static deklariert ist, so dass es wohl Performance gewinnen soll da diese nicht immer wieder neu erstellt werden muss.
                      Andererseits frage ich mich, was mir eine statische Variable bei PHP bringt, wenn nach der Scriptausführung sowieso der Speicher wieder leer ist.
                      Somit würde mir der Performancegewinn nur zur Seite stehen, sofern die Variable im selben Scriptaufruf nochmals abgefragt wird, was im Gästebuch nicht der Fall ist.

                      Bei der zweiten Variante kommt es mir hingegen sauberer vor mit der Abtrennung der AbstracClasses.
                      Dies bedeutet jedoch auch gleichzeitig erhöhten Schreibaufwand (und vllt. Performanceverlust, so dass es sinniger ist die Propertys alle in einem Model Objekt unterzubringen ?)

                      Es sind einfach einige unterschiedliche Ansätze, so dass ich mich riesig freuen würde wenn jemand jemand die Antwort darauf hat was nun besser ist:

                      Mit oder ohne solchen Abstract Classes
                      Mit oder ohne extra DbTable_Abstract Datei [Und dafür ggf. Queryzusammenbau mit "from(Tablename)" im Mapper]
                      Etc. pp..

                      Kommentar


                      • #12
                        Sehr ausführlich. Ich bevorzuge die im Quickstart beschriebene Struktur und habe dazu abstrakte Klassen entwickelt die Schreibarbeit abnehmen. Außerdem habe ich einen Project-Provider der meine Models aus der Datenbanktabelle erzeugt. Das ist auch der Grund warum ich bisher nicht auf Doctrine umgesattelt bin (auch wegen der nicht so guten Integration).

                        Das mit dem statischen $_db ist mir ein Rätsel. Wo soll das ein Perfomence-Gewinn bringen, wenn es eh nur eine Zend_Db-Instanz gibt? Und der DataMapper ist ein Singleton? Kommt selten vor, aber manchmal möchte ich zwei Dinge in einer Action separat behandeln und meine DataMapper hält dabei zwei verschiedene Models.

                        Getter/Setter sind bei mir optional und existieren aus historischen Gründen (früher behandelte ich Zend_Db_Row direkt).

                        Kommentar

                        Lädt...
                        X