Thomas: einzelne Getter oder eine Methode - Datenrückgabe Struktur

Hallo zusammen,

ich habe eine Klasse Benutzer. (nur als Beispiel)

In dieser Klasse gibt es folgende Variablen:

  • den Namen des Benutzers
  • den Namen des Computers
  • die IP Adresse des Benutzers

also zb. $username, $computername, $ipadress.
Diese sind alle als Private definiert.

Wenn ich einer dieser Informationen benötige verwende ich meine Getter:
getUsername, getComputername, getIpAdress

Alle als public definiert, da ich von außerhalb drauf zugreifen muss.

Ist das so sinnvoll?

Mir geht es darum, dass ich erst gestern gelesen habe man solle mit Public Methoden sehr sparsam umgehen. Wenn diese Klasse nun mehr Info's hat, also statt 3 z.b. 20 auf die ich von außerhalb zugreifen will, dann hätte ich 20 Getter Methode die ich dann aufrufen muss.

Sollte ich statt dessen nur eine Methode erstellen die z.b. lautet "getDaten" und die mir dann alle Daten als Array zurückgibt. In der Methode "getDaten" werden dann halt meine get Methoden aufgerufen. Wäre das sinnvoller? Dann hätte ich statt 20 nur noch 1 Methode die ich von außen aufrufen muss.

Wäre das eine sinnvolle Art der Datenrückgabe?

Grüße

  1. Hallo,

    bündele doch in Sinnzusammenhängen. Und nutze/definiere ggf. magische Methoden (__get).

    Und ja, je klarer dein Zugriff auf die Klassenvariablen definiert ist, desto übersichtlicher hast du das konstruiert.

    Gruß

    jobo

  2. Hi!

    In [einer] Klasse gibt es [...] Variablen:
    Diese sind alle als Private definiert.
    Wenn ich einer dieser Informationen benötige verwende ich meine Getter:
    Alle als public definiert, da ich von außerhalb drauf zugreifen muss.
    Ist das so sinnvoll?

    Jein. Es ist zwar in anderen Programmiersprachen so üblich, aber nicht jedes Vorgehen muss man 1:1 in andere Sprachen/Umgebungen umsetzen wollen. Jeglicher Zusatzcode verbraucht Laufzeit. Bei PHP wirkt sich das stärker aus als bei kompilierten Sprachen. Wenn du keinen Zusatznutzen von dieser Kapselung hast, würde ich das lassen.

    Mir geht es darum, dass ich erst gestern gelesen habe man solle mit Public Methoden sehr sparsam umgehen. Wenn diese Klasse nun mehr Info's hat, also statt 3 z.b. 20 auf die ich von außerhalb zugreifen will, dann hätte ich 20 Getter Methode die ich dann aufrufen muss.

    Eben.

    Sollte ich statt dessen nur eine Methode erstellen die z.b. lautet "getDaten" und die mir dann alle Daten als Array zurückgibt.

    Je nach Bedarf gebündelte Zugriffe zusätzlich zu den Einzelzugriffen zu erstellen kann sinnvoll sein. Kommt auf deine Bedürfnisse an.

    In der Methode "getDaten" werden dann halt meine get Methoden aufgerufen. Wäre das sinnvoller? Dann hätte ich statt 20 nur noch 1 Methode die ich von außen aufrufen muss.

    Das allerdings ist, den Teufel mit dem Belzebub austreiben zu wollen. Dann hast du nicht mehr nur 20 Methodenaufrufe sondern insgesamt 21.

    Lo!

    1. Hallo

      In [einer] Klasse gibt es [...] Variablen:
      Diese sind alle als Private definiert.
      Wenn ich einer dieser Informationen benötige verwende ich meine Getter:
      Alle als public definiert, da ich von außerhalb drauf zugreifen muss.
      Ist das so sinnvoll?

      Jein. Wenn du keinen Zusatznutzen von dieser Kapselung hast, würde ich das lassen.

      Ich seh halt den Vorteil darin, falls ich mal in Verbindung mit dem Auslesen der Variable etwas anderes Verknüpfen will, hätte ich mit einer eigenen GET Methode ein leichtes Spiel. Angenommen ich will die Zugriffe protokollieren. Oder ich möchte den Wert vor dem Zurückgeben abändern. Mit einer eigenen GET Methode wäre ich da flexibel.

      Sollte ich statt dessen nur eine Methode erstellen die z.b. lautet "getDaten" und die mir dann alle Daten als Array zurückgibt.

      Je nach Bedarf gebündelte Zugriffe zusätzlich zu den Einzelzugriffen zu erstellen kann sinnvoll sein. Kommt auf deine Bedürfnisse an.

      Ja, ok. Ich überleg nur gerade was schöner ist:

        
      echo $object->getName();  
        
      //oder  
        
      $array = object->getData();  
      echo $array['name'];  
      
      

      In der Methode "getDaten" werden dann halt meine get Methoden aufgerufen.

      Das allerdings ist, den Teufel mit dem Belzebub austreiben zu wollen. Dann hast du nicht mehr nur 20 Methodenaufrufe sondern insgesamt 21.

      Ja :), dass ist richtig. Aber von außen hätte ich dann nur noch eine Methode die ich aufrufen kann/muss. Also nur eine Methode als public und hätte trotzdem die Vorteile der GET Methoden da sie weiterhin Klassenintern verwendet werden.

      Aber es ist schlecht sowas immer pauschal bestimmen zu wollen. Jeder findet etwas anderes schön und elegant. Ich dachte nur das es da vielleicht schon gewisse Standards gibt.

      Grüße

      1. Hi!

        Ich seh halt den Vorteil darin, falls ich mal in Verbindung mit dem Auslesen der Variable etwas anderes Verknüpfen will, hätte ich mit einer eigenen GET Methode ein leichtes Spiel. Angenommen ich will die Zugriffe protokollieren. Oder ich möchte den Wert vor dem Zurückgeben abändern. Mit einer eigenen GET Methode wäre ich da flexibel.

        Du musst selbst einschätzen, wie realistisch oder hypothetisch diese Szenarien sind. Flexibilität kommt immer mit einer höheren Komplexität daher, die sich im erhöhten Rechenaufwand widerspiegelt. Letzterem kann man mit schnellerer Hardware begegnen, die Komplexität im Code und dessen Wartung bleibt.

        Ein Kompromiss wäre, zunächst einmal die Eigenschaften auf public zu setzen, für die auf absehbare Zeit kein zusätzlicher Code im Getter/Setter geplant ist. Wenn dann doch der Fall eintritt, kann man die Eigenschaft umbenennen (zum Beispiel mit _ davor), sie private machen und mittels __get()/__set()-Overloading implizite Getter/Setter hinzufügen.

        Außerdem gibt es Software-Pattern wie den Decorator.

        Ja, ok. Ich überleg nur gerade was schöner ist:

        echo $object->getName();

        //oder
        $array = object->getData();
        echo $array['name'];

          
        Hinzu kommt noch, was praktischer ist. Eine entsprechende IDE kann bei Eigenschaften und Methoden eines Objekts automatisch Code vervollständigen, wenn dessen Klassendefinition bekannt ist. Bei Array-Keys geht das nicht, denn die sind nur Strings, und welche davon im Array sind, ist zur Programmierzeit auch nicht unbedingt der IDE bekannt.  
          
        Im Grunde ist diese Überlegung aber nicht notwendig, denn wenn du Einzelzugriffe haben willst, musst du nicht über den Umweg eines gemeinsamen Abrufs und anschließender Separierung gehen. Ein gemeinsamer Abruf ist nur dann sinnvoll, wenn die Daten (oder ein Teil davon) gemeinsam weitergegeben werden sollen.  
          
        
        > > Dann hast du nicht mehr nur 20 Methodenaufrufe sondern insgesamt 21.  
        > Aber von außen hätte ich dann nur noch eine Methode die ich aufrufen kann/muss. Also nur eine Methode als public und hätte trotzdem die Vorteile der GET Methoden da sie weiterhin Klassenintern verwendet werden.  
          
        Es geht in der von dir gelesenen Empfehlung vermutlich nicht darum, wieviele Methoden public sind oder nicht, sondern wieviele zur Erledigung der Aufgabe aufgerufen werden müssen.  
          
        
        > Aber es ist schlecht sowas immer pauschal bestimmen zu wollen. Jeder findet etwas anderes schön und elegant. Ich dachte nur das es da vielleicht schon gewisse Standards gibt.  
          
        Bei Java ist es ein Standard, mit definiert benannten Gettern und Settern zu arbeiten, da einige Bibliotheken auf diese Konventionen abgestimmt sind. Für PHP gibt es einen derartigen übergreifenden Standard nicht.  
          
          
        Lo!
        
        1. Hallo,

          Bei Java ist es ein Standard, mit definiert benannten Gettern und Settern zu arbeiten, da einige Bibliotheken auf diese Konventionen abgestimmt sind. Für PHP gibt es einen derartigen übergreifenden Standard nicht.

          Wobei in Frameworks wie Zend doch damit auf die Eigenschaften einer Klasse zugegriffen wird. Somit ist klar, dass für alles, was gegetted und gesetted werden kann, eine Methode dafür da sein sollte. Somit sieht man an den gettern und settern, was die Klasse kann und welche Konfigurationen sie zulässt. Über eine Liste von Eigenschaften, zB. eines "Besuchers", möchte man dann vielleicht iterieren. Insofern bietet sich als Rückgabewert ein assoziatives Array oder eben Object an. Eeine Klassen-Methode wie "getModules" wird sowas wohl liefern, oder besser ein einfaches Array.

          Gruß

          jobo

          1. Hi!

            Bei Java ist es ein Standard, mit definiert benannten Gettern und Settern zu arbeiten, da einige Bibliotheken auf diese Konventionen abgestimmt sind. Für PHP gibt es einen derartigen übergreifenden Standard nicht.
            Wobei in Frameworks wie Zend doch damit auf die Eigenschaften einer Klasse zugegriffen wird. Somit ist klar, dass für alles, was gegetted und gesetted werden kann, eine Methode dafür da sein sollte. Somit sieht man an den gettern und settern, was die Klasse kann und welche Konfigurationen sie zulässt.

            Ich sehe auch, wenn eine les- und schreibbare Eigenschaft public ist, dass man darauf zugreifen darf. Dazu brauch ich vom Prinzip her keinen Getter/Setter. Sollte dein zweiter Satz sowas wie eine Gesetzmäßigkeit beschreiben? Wenn ja, so kann ich dem nicht zustimmen. Das ZF ist keine Instanz, die Coding-Standards verbindlich oder auch nur durch die Macht des Faktischen festlegen kann.

            Am besten von den mir bekannten Sprachen finde ich das bei C# gelöst. Da gibt es Propertys, die wie öffentliche Objektvariablen angesprochen werden. Getter und Setter werden direkt der Property hinzugefügt und sind nach außen hin nicht sichtbar. Wenn man bisher eine öffentliche Objektvariable hatte und nun eine komplexere Zugriffslogik haben möchte, schreibt man diese Variable in eine Property um und muss keinen Code ändern, der darauf zugegriffen hat.

            Deklaration einer Objektvariablen:
            public string Foo;

            Zugriff darauf:
            instanz.Foo = ...

            Deklaration einer Property:
            public string Foo {
              get {...}
              set {...}
            }

            Zugriff darauf:
            instanz.Foo = ...

            Wenn ein Getter oder Setter nichts weiter macht, als auf eine private Variable zuzugreifen, so kann man sich auch das explizite Deklarieren dieser privaten Variable sparen und die Property als Einzeiler anlegen.

            public string Foo { get; set; }

            Auch öffentlich nur lesbare Propertys kann man mit der Kurzform anlegen.
            public string Foo { get; private set; }

            Nunja, PHPs OOP ist eine nette Dreingabe, die man nicht mit von anderen Systemen bekannten Vorgehensweisen überstrapazieren sollte.

            Über eine Liste von Eigenschaften, zB. eines "Besuchers", möchte man dann vielleicht iterieren. Insofern bietet sich als Rückgabewert ein assoziatives Array oder eben Object an. Eeine Klassen-Methode wie "getModules" wird sowas wohl liefern, oder besser ein einfaches Array.

            In der Vergangenheit wollte ich selten über alle Eigenschaften eines Objekts iterieren. Das kommt vielleicht vor, wenn das Objekt in Gänze persistiert werden soll, oder wenn man eine selbst formatierte Kontrollausgabe erzeugen will. Was besser ist oder nicht hängt vom konkreten Einsatzfall ab. Das kann ein Array sein, das kann ein Objekt sein, das kann aber auch ein Iterator aus der SPL sein. Beim Objekt hast du aber wieder das Problem, wenn du strikt Coding-Style-kompatibel zum ZF sein willst, dass du dann Getter und Setter schreiben solltest und mit diesen keine Typkonvertierung nach array vornehmen kannst. Im Allgemeinen halte ich es aber für programmiertechnischen Unsinn, wenn eine Klasse, die Eigenschaften und Methoden zu einem bestimmten Thema bereitstellt, ein Objekt oder Array liefert, das nichts weiter als die reinen Daten ihrer selbst beinhaltet. Dann schon lieber einen Iterator oder ähnliches, aber eingebettetes Konstrukt.

            Lo!

            1. Hallo,

              Ich sehe auch, wenn eine les- und schreibbare Eigenschaft public ist, dass man darauf zugreifen darf.

              Davon gibt es aber fast keine, hätte ich jetzt gemeint.

              Am besten von den mir bekannten Sprachen finde ich das bei C# gelöst.

              ... Getter und Setter werden direkt der Property hinzugefügt und sind nach außen hin nicht sichtbar. ... Nunja, PHPs OOP ist eine nette Dreingabe, die man nicht mit von anderen Systemen bekannten Vorgehensweisen überstrapazieren sollte.

              Naja, ich meine, dass du mit __get den selben Effekt erreichen kannst.

              In der Vergangenheit wollte ich selten über alle Eigenschaften eines Objekts iterieren.

              Nee, aber du willst vielleicht doch auf das Objekt zugreifen (können). Request-Object. Oder Dispatcher? Dann aber nicht zum iterieren.

              Beim Objekt hast du aber wieder das Problem, wenn du strikt Coding-Style-kompatibel zum ZF sein willst, dass du dann Getter und Setter schreiben solltest und mit diesen keine Typkonvertierung nach array vornehmen kannst.

              Dispatcher::getInstance()->getRequest()->getParams(); so in der Art hätte ich gedacht. Die Instanz vom Dispatcher ermöglicht den Zugriff auf das Request-Objekt, welches wieder über getParams() ein Array(!) der Paramenter, vielleicht assoziativ, wiedergibt.

              Im Allgemeinen halte ich es aber für programmiertechnischen Unsinn, wenn eine Klasse, die Eigenschaften und Methoden zu einem bestimmten Thema bereitstellt, ein Objekt oder Array liefert, das nichts weiter als die reinen Daten ihrer selbst beinhaltet.

              Das würde ich auch meinen. ->fetchAllEntries(ASSOC) sollte die Methode einer Model-Klasse sein, die alle Daten als assoziatives Array wiedergibt.

              Dann schon lieber einen Iterator oder ähnliches, aber eingebettetes Konstrukt.

              Der Iterator verwurstet doch Arraykonstruktionen, oder? Bzw. kann mit dem IteratorIterator rekursiv zB. das Ergebnis von scandir() durchlaufen.

              Gruß

              jobo

              1. Hi!

                Ich sehe auch, wenn eine les- und schreibbare Eigenschaft public ist, dass man darauf zugreifen darf.
                Davon gibt es aber fast keine, hätte ich jetzt gemeint.

                Ich meinte das nicht speziell auf das ZF bezogen sondern allgemein.

                Am besten von den mir bekannten Sprachen finde ich das bei C# gelöst.
                ... Getter und Setter werden direkt der Property hinzugefügt und sind nach außen hin nicht sichtbar.
                Naja, ich meine, dass du mit __get den selben Effekt erreichen kannst.

                Jein, nur indirekt. Das Ergebnis ist das gleiche, aber es ist wesentlich unübersichtlicher, mit nur je einer __get() und __set()-Methode pro Klasse alle Eigenschaften behandeln zu müssen. Auch dann, wenn man sie nur als Dispatcher verwendet und die eigentliche Zugriffslogik in einzelne Methoden auslagert. Sie liegen dann ja auch nur lose in der Klasse rum und sind nicht direkt mit Syntaxelementen an einen Eigenschaftenname gebunden. Da letzerer auch nicht mit Code deklariert ist, kann er auch nicht von IDEs zwecks Autovervollständigung erkannt werden. Dazu muss man Spezialkniffe mit Dokumentationskommentaren verwenden, die aber auch nicht von allen PHP-IDEs berücksichtigt werden.

                In der Vergangenheit wollte ich selten über alle Eigenschaften eines Objekts iterieren.
                Nee, aber du willst vielleicht doch auf das Objekt zugreifen (können).

                Ja, und zwar so wie das eigentlich vorgesehen war, auf einzelne Methoden und auch Eigenschaften, ohne umständliche Getter/Setter, wenn das nicht notwendig ist.

                Dispatcher::getInstance()->getRequest()->getParams(); so in der Art hätte ich gedacht. Die Instanz vom Dispatcher ermöglicht den Zugriff auf das Request-Objekt, welches wieder über getParams() ein Array(!) der Paramenter, vielleicht assoziativ, wiedergibt.

                Das ist ein Array mit Daten drin, ohne dass dazu ein Objekt existiert. Das ist so in Ordnung, aber die Eigenschaften eines Objekt über ein Daten-Array bereitzustellen, allein zum Zwecke ihres normalen Zugriffs, ist schon ziemlich unpraktisch.

                Der Iterator verwurstet doch Arraykonstruktionen, oder?

                Ein Iterator liefert Daten in sequenzieller Form, wenn man sie in einer solchen benötigt. Von außen gesehen sieht das wie das Iterieren über ein Array aus, aber ansonsten ist die Implementation des Iterators nach Belieben gestaltbar. Man könnte beispielsweise eine foreach-Schleife haben, die normalerweise mit Arrays gefüttert wird, der man aber nun die Ergebnismenge aus einer Datenbankabfrage übergeben will. In ein Array fetchen und dieses übergeben ist eine (speicherverbrauchende) Möglichkeit. Eine andere ist ein Iterator, der bei jedem Schritt einen Fetch-Aufruf durchführt und den dabei gewonnenen Datensatz liefert.

                Übrigens, wenn man sich das Erstellen von zwei Methoden pro Eigenschaft ersparen will, kann man Getter und Setter auch in einer Methode kombinieren:

                class Foo {

                private $bar;

                function Bar($value = null) {
                    if ($value != null)
                      $this->bar = $value; // oder eine komplexere Schreiblogik

                return $this->bar; // oder eine komplexere Leselogik
                  }
                }

                $qux = $foo->Bar(); // Lesen
                $foo->Bar('baz'); // Schreiben

                Der Nachteil an dieser Lösung ist, dass nicht eindeutig zwischen Schreib- und Lesezugriff unterschieden werden kann. Wenn $value gleich null ist, dann ist es ein Lesezugriff. Wenn er ungleich null ist, ist es ein Schreibzugriff, kann aber auch ein kombinierter Schreib-Lese-Zugriff sein. Man kann nicht innerhalb einer Methode feststellen, ob der Rückgabewert vom Aufrufer verwendet wird oder nicht. Bei einem reinen Schreibzugriff wird also eine komplexere Leselogik jedes Mal mit ausgeführt.

                Lo!

                1. Hallo,

                  Ich sehe auch, wenn eine les- und schreibbare Eigenschaft public ist, dass man darauf zugreifen darf.
                  Davon gibt es aber fast keine, hätte ich jetzt gemeint.

                  Ich meinte das nicht speziell auf das ZF bezogen sondern allgemein.

                  Naja, man mag sich fragen, ob das eben so schlau ist. Bei c# definierst du das ja auch. Das "sollte" man bei PHP vielleicht auch so machen, dass Objekte/Klassen den Zugang zu Daten via get/set bewerkstelligen.

                  Jein, nur indirekt. Das Ergebnis ist das gleiche, aber es ist wesentlich unübersichtlicher, mit nur je einer __get() und __set()-Methode pro Klasse alle Eigenschaften behandeln zu müssen. Auch dann, wenn man sie nur als Dispatcher verwendet und die eigentliche Zugriffslogik in einzelne Methoden auslagert. Sie liegen dann ja auch nur lose in der Klasse rum und sind nicht direkt mit Syntaxelementen an einen Eigenschaftenname gebunden. Da letzerer auch nicht mit Code deklariert ist, kann er auch nicht von IDEs zwecks Autovervollständigung erkannt werden. Dazu muss man Spezialkniffe mit Dokumentationskommentaren verwenden, die aber auch nicht von allen PHP-IDEs berücksichtigt werden.

                  Das mag sein. Wobei die Übersicht ja ggf. auch damit zusammenhängt, ob ich vielleicht nur ein paar Ausnahmen habe, die ich über __get/set regele.

                  Ja, und zwar so wie das eigentlich vorgesehen war, auf einzelne Methoden und auch Eigenschaften, ohne umständliche Getter/Setter, wenn das nicht notwendig ist.

                  Naja, active-record wäre das dann, oder? Kann sein, muss nicht. Dann regelt die Klasse den Zugriff auf die Datensätze, oder? ZF kennt auch eine DB_Row-Klasse glaub ich. Aber fetchAssoc() gibt bestimmt die Zeilenwerte als assoziatives _Array_ wieder.

                  Das ist ein Array mit Daten drin, ohne dass dazu ein Objekt existiert. Das ist so in Ordnung, aber die Eigenschaften eines Objekt über ein Daten-Array bereitzustellen, allein zum Zwecke ihres normalen Zugriffs, ist schon ziemlich unpraktisch.

                  Ne. Ein Objekt ist ja in dem Sinne kein Datensatz, sondern der Datensatzverwalter. Oder muss es nicht sein. Verwaltet es sich selbst, ist active-Record, hätte ich jetzt gemeint. Aber dann hast du u.U. auch wieder die Iterationsprobleme. Auf einzelne Vars gezielt zuzugreifen (getId()) ist dann u.U. auch über getter nicht falsch. Denn dabei definierst Du ja auch kein offenens Regal, an dem sich "jeder" bedienen kann, wie und wann er will, sondern gibts strukturierten Zugriff vor.

                  class Foo {

                  private $bar;

                  function Bar($value = null) {
                      if ($value != null)
                        $this->bar = $value; // oder eine komplexere Schreiblogik

                  return $this->bar; // oder eine komplexere Leselogik
                    }
                  }

                  $qux = $foo->Bar(); // Lesen
                  $foo->Bar('baz'); // Schreiben

                  Der Nachteil an dieser Lösung ist, dass nicht eindeutig zwischen Schreib- und Lesezugriff unterschieden werden kann. Wenn $value gleich null ist, dann ist es ein Lesezugriff. Wenn er ungleich null ist, ist es ein Schreibzugriff, kann aber auch ein kombinierter Schreib-Lese-Zugriff sein. Man kann nicht innerhalb einer Methode feststellen, ob der Rückgabewert vom Aufrufer verwendet wird oder nicht. Bei einem reinen Schreibzugriff wird also eine komplexere Leselogik jedes Mal mit ausgeführt.

                  Wenn Foo fürs Lesen und Schreiben verantwortlich ist, dann sollte die Klasse genau das tun. Ob sie die Werte, die sie schreibt und liest innerhalb der Funktion dass dann als $_bar oder $_baz abspeichert, ist privat. Denn da die Klasse fürs Lesen und Schreiben zuständig ist, nimmt sie Parameter fürs Lesen entgegen und gibt Daten (i.d.R.) als Array oder Einzelwerte zurück. Oder übernimmt Daten als Array oder Objekt und weiß dann, was damit zu tun ist. So hätte ich das jetzt verstanden.

                  Gruß

                  jobo

                  1. Hallo,

                    Naja, active-record wäre das dann, oder? Kann sein, muss nicht. Dann regelt die Klasse den Zugriff auf die Datensätze, oder? ZF kennt auch eine DB_Row-Klasse glaub ich. Aber fetchAssoc() gibt bestimmt die Zeilenwerte als assoziatives _Array_ wieder.

                    http://framework.zend.com/manual/de/zend.db.table.row.html

                    bzw.

                    http://framework.zend.com/apidoc/core/ und darin eben die Klasse:

                    http://framework.zend.com/apidoc/core/Zend_Db/Table/Zend_Db_Table_Row.html

                    Der Zugriff auf Daten ist über die Methoden geregelt. __get/set wird auch - wie ich finde garnicht so unübersichtlich - genutzt.

                      
                    abstract class Zend_Db_Table_Row_Abstract implements ArrayAccess  
                    {  
                      
                        /**  
                         * The data for each column in the row (column_name => value).  
                         * The keys must match the physical names of columns in the  
                         * table for which this row is defined.  
                         *  
                         * @var array  
                         */  
                        protected $_data = array();  
                      
                        /**  
                         * This is set to a copy of $_data when the data is fetched from  
                         * a database, specified as a new tuple in the constructor, or  
                         * when dirty data is posted to the database with save().  
                         *  
                         * @var array  
                         */  
                        protected $_cleanData = array();  
                      
                        /**  
                         * Tracks columns where data has been updated. Allows more specific insert and  
                         * update operations.  
                         *  
                         * @var array  
                         */  
                        protected $_modifiedFields = array();  
                      
                        /**  
                         * Zend_Db_Table_Abstract parent class or instance.  
                         *  
                         * @var Zend_Db_Table_Abstract  
                         */  
                        protected $_table = null;  
                      
                        /**  
                         * Connected is true if we have a reference to a live  
                         * Zend_Db_Table_Abstract object.  
                         * This is false after the Rowset has been deserialized.  
                         *  
                         * @var boolean  
                         */  
                        protected $_connected = true;  
                      
                        /**  
                         * A row is marked read only if it contains columns that are not physically represented within  
                         * the database schema (e.g. evaluated columns/Zend_Db_Expr columns). This can also be passed  
                         * as a run-time config options as a means of protecting row data.  
                         *  
                         * @var boolean  
                         */  
                        protected $_readOnly = false;  
                      
                        /**  
                         * Name of the class of the Zend_Db_Table_Abstract object.  
                         *  
                         * @var string  
                         */  
                        protected $_tableClass = null;  
                      
                        /**  
                         * Primary row key(s).  
                         *  
                         * @var array  
                         */  
                        protected $_primary;  
                      
                    ...  
                      
                    //////  
                    //////  
                    ////// alles nur protected bis hierher ...  
                    //////  
                    //////  
                    ...  
                    ///// zentrale Methode __get regelt den Zugriff auf protected vars:  
                      
                      
                        /**  
                         * Retrieve row field value  
                         *  
                         * @param  string $columnName The user-specified column name.  
                         * @return string             The corresponding column value.  
                         * @throws Zend_Db_Table_Row_Exception if the $columnName is not a column in the row.  
                         */  
                        public function __get($columnName)  
                        {  
                            $columnName = $this->_transformColumn($columnName);  
                            if (!array_key_exists($columnName, $this->_data)) {  
                                require_once 'Zend/Db/Table/Row/Exception.php';  
                                throw new Zend_Db_Table_Row_Exception("Specified column \"$columnName\" is not in the row");  
                            }  
                            return $this->_data[$columnName];  
                        }  
                      
                    ...  
                      
                    
                    

                    Gruß

                    jobo

                    1. Hi!

                      Der Zugriff auf Daten ist über die Methoden geregelt. __get/set wird auch - wie ich finde garnicht so unübersichtlich - genutzt.

                      Das liegt daran, dass du dort _eine_, relativ übersichtliche Regel hast, die zum Feldnamen das Datum sucht. Wenn die Regeln aber für jede Eigenschaft andere sind, hast du das nicht mehr in 5 Zeilen gelöst.

                      Lo!

                      1. Hallo,

                        Der Zugriff auf Daten ist über die Methoden geregelt. __get/set wird auch - wie ich finde garnicht so unübersichtlich - genutzt.

                        Das liegt daran, dass du dort _eine_, relativ übersichtliche Regel hast, die zum Feldnamen das Datum sucht. Wenn die Regeln aber für jede Eigenschaft andere sind, hast du das nicht mehr in 5 Zeilen gelöst.

                        Ich hätte jetzt gedacht, dass es sinnvoll ist oder sein kann, das dennoch an einer Stelle zu machen. Ggf. auch, an weitere private Funktionen weiterzuleiten oder ähnliches wie Validierung der Eingabe.

                        Gruß

                        jobo

                  2. Hi!

                    Naja, man mag sich fragen, ob das eben so schlau ist. Bei c# definierst du das ja auch. Das "sollte" man bei PHP vielleicht auch so machen, dass Objekte/Klassen den Zugang zu Daten via get/set bewerkstelligen.

                    Es geht mir im Wesentlichen um Aufwandsreduktion und um das Kleinhalten der Komplexität. Die Property-Kurzschreibweise gab es in C# nicht von Anfang an. Damals habe ich sie auch gemieden, wenn es ging, obwohl das Visual Studio ein Snippet bereitstellte, mit dem sich der Tipp-Aufwand für den Programmierer in Grenzen hielt. Man merkte diese zusätzlichen Schritte spätestens beim Debugging wieder, wenn bei Einzelschrittabarbeitung eine "einfache Zuweisung" ansteht, die normalerweise in einem Schritt erledigt ist, und der Debugger den Umweg durch den Setter geht, in dem nichts weiter als "private_variable = value" steht.

                    Das ist ein Array mit Daten drin, ohne dass dazu ein Objekt existiert. Das ist so in Ordnung, aber die Eigenschaften eines Objekt über ein Daten-Array bereitzustellen, allein zum Zwecke ihres normalen Zugriffs, ist schon ziemlich unpraktisch.

                    Ne. Ein Objekt ist ja in dem Sinne kein Datensatz, sondern der Datensatzverwalter. Oder muss es nicht sein.

                    So ist es aber, abseits aller Pattern, die sich im Lauf der Zeit dazuentwickelten, gedacht gewesen, dass es Datensatz und Verwalter in einem ist. Sonst hätte man gleich bei der Trennung nach Daten und Funktionen bleiben können.

                    Wenn Foo fürs Lesen und Schreiben verantwortlich ist, dann sollte die Klasse genau das tun.

                    Es ging mir nicht um die Klassenebene, ich hätte das class drumherum doch weglassen sollen, sondern um einen etwas reduzierteren Aufwand, dass man bei der Anwendung nicht nach getBar() und setBar() trennen muss sondern einfach nur Bar() für beides benutzen kann.

                    Lo!

                    1. Hallo,

                      So ist es aber, abseits aller Pattern, die sich im Lauf der Zeit dazuentwickelten, gedacht gewesen, dass es Datensatz und Verwalter in einem ist. Sonst hätte man gleich bei der Trennung nach Daten und Funktionen bleiben können.

                      Naja, kann es ja sein, dennoch hast du doch recht schnell auch Daten unterschiedlichen Typs, zB. Systemvariablen (Gruppenzugehörigkeit, ID, Verlaufsdaten etc.) und vielleicht auch vom Nutzer konfigurierbare Daten. Für eine Datensammlung wäre dann ein Array eher sinnvoll, oder könnte es sein.

                      $_id = null;
                      $_system = array();
                      $_userdata = array();

                      Es ging mir nicht um die Klassenebene, ich hätte das class drumherum doch weglassen sollen, sondern um einen etwas reduzierteren Aufwand, dass man bei der Anwendung nicht nach getBar() und setBar() trennen muss sondern einfach nur Bar() für beides benutzen kann.

                      Naja, aber versteckst du dann nicht die Bezeichnung oder was die Funktion kann im Namen. Und sollte nicht immer jede Funktion nur eine Sache können? Ist vielleicht auch vom Bedarfsfall und Geschmack abhhängig.

                      new Product("Autor","Titel","Preis","Shortdesc","Ustklasse","basename","ISBN") aber zB. macht aus meiner Sicht nicht allzuviel Sinn oder nicht unbedingt.

                      Eher $Producthandler::getInstance()->addProduct(array("autor"=>"Hans","title="Titel1" etc.pp.));

                      Der kann dann dem Produkte gleich noch zusätzlich eine interne ID verpassen, ein Einstellungsdatum, vielleicht auch wer es eingepflegt hat etc.pp., also Systemdaten oder Metadaten hinzufügt. Würde das Produkt das selber machen, wäre es ein ActiveRecord, was ja auch eins von den vielen Fowler-Pattern ist und glaub ich auch im ZF vorkommt. Die schreiben ja immer dazu, welches Pattern sie umsetzen, wenn sie es tun (;-).

                      Gruß

                      jobo

                      1. Hi!

                        So ist es aber, abseits aller Pattern, die sich im Lauf der Zeit dazuentwickelten, gedacht gewesen, dass es Datensatz und Verwalter in einem ist. Sonst hätte man gleich bei der Trennung nach Daten und Funktionen bleiben können.
                        Naja, kann es ja sein, dennoch hast du doch recht schnell auch Daten unterschiedlichen Typs, zB. Systemvariablen (Gruppenzugehörigkeit, ID, Verlaufsdaten etc.) und vielleicht auch vom Nutzer konfigurierbare Daten. Für eine Datensammlung wäre dann ein Array eher sinnvoll, oder könnte es sein.

                        Ich sehe nicht, worauf du hinauswillst. Die Strukturierung der Objekte nach Zuständigkeiten ist ein architekturelles Problem eines bestimmten Anwendungsfalles. Das Separierieren nach Aufgaben ist eine wichtige Design-Entscheidungsfrage, aber je nach Fall können verschiedene Dinge alles eine Soße sein und ein anderes Mal muss man sie noch in sich aufteilen. Das hat aber wenig damit zu tun, dass man nach der grundlegenden OOP-Philosophie Daten und deren Methoden in ein Gebilde zusammenfassen soll.

                        Es ging mir [...] um einen etwas reduzierteren Aufwand, dass man bei der Anwendung nicht nach getBar() und setBar() trennen muss sondern einfach nur Bar() für beides benutzen kann.
                        Naja, aber versteckst du dann nicht die Bezeichnung oder was die Funktion kann im Namen. Und sollte nicht immer jede Funktion nur eine Sache können? Ist vielleicht auch vom Bedarfsfall und Geschmack abhhängig.

                        Wie gesagt, ich finde ja schon das übertriebene Trennen in Lese- und Schreib-Vorgang unsinnig. Noch schlimmer wird es meiner Meinung nach, wenn beispielsweise wegen einer alphabetischen Sortierung ein Getter nicht mehr in unmittelbarer Nachbarschaft zum Setter im Quellcode notiert ist. Das erschwert die Erfassung der Sinn-Zusammenhänge noch mehr, und das bei sowieso schon aufgeblähtem Code. Wenn man da keine IDE mit einklappbaren Codeteilen hat ...

                        new Product("Autor","Titel","Preis","Shortdesc","Ustklasse","basename","ISBN") aber zB. macht aus meiner Sicht nicht allzuviel Sinn oder nicht unbedingt.

                        Eher $Producthandler::getInstance()->addProduct(array("autor"=>"Hans","title="Titel1" etc.pp.));

                        Der kann dann dem Produkte gleich noch zusätzlich eine interne ID verpassen, ein Einstellungsdatum, vielleicht auch wer es eingepflegt hat etc.pp., also Systemdaten oder Metadaten hinzufügt.

                        Warum soll man das in einem Konstruktor nicht machen können/dürfen? Der ist für die Initialisierung der Eigenschaften eines Objekts zuständig.

                        Lo!

                        1. Hallo,

                          ...  Das hat aber wenig damit zu tun, dass man nach der grundlegenden OOP-Philosophie Daten und deren Methoden in ein Gebilde zusammenfassen soll.

                          Naja, die Frage war oder wäre für mich, ob ein Produkt wirklich als Klasse abgebildet wird, oder ein Datensatz (Array) in einer Klasse ist.

                          Wie gesagt, ich finde ja schon das übertriebene Trennen in Lese- und Schreib-Vorgang unsinnig.

                          Nun ja, beim Schreiben und Lesen dachte ich, das sei schon genau das Gegenteil. Irgendwelche Shortcuts kannst Du dir ja nach belieben immer Bauen.

                          Noch schlimmer wird es meiner Meinung nach, wenn beispielsweise wegen einer alphabetischen Sortierung ein Getter nicht mehr in unmittelbarer Nachbarschaft zum Setter im Quellcode notiert ist.

                            
                          /**  
                               * Returns the table object, or null if this is disconnected row  
                               *  
                               * @return Zend_Db_Table_Abstract|null  
                               */  
                              public function getTable()  
                              {  
                                  return $this->_table;  
                              }  
                            
                              /**  
                               * Set the table object, to re-establish a live connection  
                               * to the database for a Row that has been de-serialized.  
                               *  
                               * @param Zend_Db_Table_Abstract $table  
                               * @return boolean  
                               * @throws Zend_Db_Table_Row_Exception  
                               */  
                              public function setTable(Zend_Db_Table_Abstract $table = null)  
                              {  
                                  if ($table == null) {  
                                      $this->_table = null;  
                                      $this->_connected = false;  
                                      return false;  
                                  }  
                            
                                  $tableClass = get_class($table);  
                                  if (! $table instanceof $this->_tableClass) {  
                                      require_once 'Zend/Db/Table/Row/Exception.php';  
                                      throw new Zend_Db_Table_Row_Exception("The specified Table is of class $tableClass, expecting class to be instance of $this->_tableClass");  
                                  }  
                            
                                  $this->_table = $table;  
                                  $this->_tableClass = $tableClass;  
                            
                                  $info = $this->_table->info();  
                            
                                  if ($info['cols'] != array_keys($this->_data)) {  
                                      require_once 'Zend/Db/Table/Row/Exception.php';  
                                      throw new Zend_Db_Table_Row_Exception('The specified Table does not have the same columns as the Row');  
                                  }  
                            
                                  if (! array_intersect((array) $this->_primary, $info['primary']) == (array) $this->_primary) {  
                            
                                      require_once 'Zend/Db/Table/Row/Exception.php';  
                                      throw new Zend_Db_Table_Row_Exception("The specified Table '$tableClass' does not have the same primary key as the Row");  
                                  }  
                            
                                  $this->_connected = true;  
                                  return true;  
                              }  
                            
                          
                          

                          Das erschwert die Erfassung der Sinn-Zusammenhänge noch mehr, und das bei sowieso schon aufgeblähtem Code. Wenn man da keine IDE mit einklappbaren Codeteilen hat ...

                          new Product("Autor","Titel","Preis","Shortdesc","Ustklasse","basename","ISBN") aber zB. macht aus meiner Sicht nicht allzuviel Sinn oder nicht unbedingt.

                          Eher $Producthandler::getInstance()->addProduct(array("autor"=>"Hans","title="Titel1" etc.pp.));

                          Der kann dann dem Produkte gleich noch zusätzlich eine interne ID verpassen, ein Einstellungsdatum, vielleicht auch wer es eingepflegt hat etc.pp., also Systemdaten oder Metadaten hinzufügt.

                          Warum soll man das in einem Konstruktor nicht machen können/dürfen? Der ist für die Initialisierung der Eigenschaften eines Objekts zuständig.

                          Klar. Das wäre dann der Active Record. http://framework.zend.com/wiki/display/ZFPROP/Zend_Db_ActiveRecord

                          Gruß

                          jobo

                          1. Hallo,

                            new Product("Autor","Titel","Preis","Shortdesc","Ustklasse","basename","ISBN") aber zB. macht aus meiner Sicht nicht allzuviel Sinn oder nicht unbedingt.

                            Eher $Producthandler::getInstance()->addProduct(array("autor"=>"Hans","title="Titel1" etc.pp.));

                            Der kann dann dem Produkte gleich noch zusätzlich eine interne ID verpassen, ein Einstellungsdatum, vielleicht auch wer es eingepflegt hat etc.pp., also Systemdaten oder Metadaten hinzufügt.

                            Warum soll man das in einem Konstruktor nicht machen können/dürfen? Der ist für die Initialisierung der Eigenschaften eines Objekts zuständig.

                            Klar. Das wäre dann der Active Record. http://framework.zend.com/wiki/display/ZFPROP/Zend_Db_ActiveRecord

                            Aber im Wesentlichen erstmal mit

                            "... The Zend_Db_Table solution is an implementation of the Table Data Gateway
                            http://www.martinfowler.com/eaaCatalog/tableDataGateway.html pattern. The solution also includes a class that implements the Row Data Gateway
                            http://www.martinfowler.com/eaaCatalog/rowDataGateway.html pattern.

                            Gruß

                            jobo