dr.Colossos: get_class_vars() Problem

Hi,

ich moechte Objekte ohne viel Code aus Datenbank-Tabellen erstellen.

Nehmen wir mal die Tabelle Personen an, aus deren Eintraegen ich Objekte erstellen moechte.

Ich faend es recht fein, wenn ich die Member-Variablen (z.B. Name, Vorname, etc). nicht explizit initialisieren muesste ...

[...]
$this->name = $db->value['name']
$this->vorname = $db->value['vorname']
[...]

... sondern dass ueber eine Schleife machen koennte.

Da ich das nicht nur bei einer Klasse machen will, sondern bei mehreren, bietet es sich an die Methode die das macht in eine Oberklasse zu schieben, und im Konstruktor der Unterklasse aufzurufen.

Sieht in etwa so aus:
Unterklasse ruft assign_members($db_data) auf, welche in Oberklasse definiert ist
$db_data ist ein assoziatives Array der Form $db_data['name'] = 'Dr.Colossos'
Die Werte mit den keys des Arrays die mit Members uebereinstimmen, werden gesetzt ... unten steht der Code.

class Person extends AssignmentClass
{
 protected function assign_members($db_data)
 {
  $members = get_class_vars(get_class($this));
  foreach($db_data as $field_name => $value)
  {
   if(array_key_exists($field_name, $members))
    $this->$field_name = $value;
   // TODO: throw Exception here ...
   else
    echo '<h1>ERROR! member "'.$field_name.'" is not definded!</h1>';
  }
 }
}

class Person extends AssignmentClass
{
 private $name = null;
 private $vorname = null;
 [...]
 public function __construct($db_data)
 {
  $this->assign_members($db_$data);
 }
 [...]
}

Problem ist nun, dass mir get_class_vars(get_class($this)); keine private Members liefert, obwohl der AUFRUF der Methode assign_members() in der abzufragenden Klasse (Person) ist.

Wie ist das mit der Vererbung in PHP? Kann man diese Problem (sauber)  umgehen?

ich denke das Problem ist, dass assign_members() eine Methode der Oberklasse ist ... sollte zwar runter-vererbt werden, aber is wohl nicht so.

Wenn ich die Methode assign_members() in die Klasse Person kopiere funktionierts einwandfrei. Aber wenn ich viele derartige Klassen habe, dann waer's unsinnig in jeder dieser eine Methode assign_members() zu haben.

Hat da jemand eine Idee?

Mein work-around waere ein getter in der Unterklasse der get_class_vars(get_class($this)); zurueckliefert, und assign_members() der Oberklasse auf den Daten arbeiten laesst ... gefaellt mir aber nicht so wirklich.

Danke fuer eure Hilfe!

  1. echo $begrüßung;

    Nehmen wir mal die Tabelle Personen an, aus deren Eintraegen ich Objekte erstellen moechte.
    Ich faend es recht fein, wenn ich die Member-Variablen (z.B. Name, Vorname, etc). nicht explizit initialisieren muesste ...

    Dann hätte ich einen Vorschlag, der ohne viel Aufwand daherkommt. Ich hoffe, er ist zusammen mit den Kommentaren selbsterklärend.

    class DbRecord {  
      // Feldnamen aus der Datenbank, wird durch spezialisierte Klasse überschrieben  
      protected $_fieldnames = array();  
      // Ablage für Datenbankwerte  
      protected $_values = array();  
      
      // magische Methode für den Zugriff auf die Datenbank-Felder  
      function __get($key) {  
        // wenn in _fieldnames aufgeführt und in den Datenbankwerten enthalten  
        if (in_array($key, $this->_fieldnames) and isset($this->_values[$key]))  
          return $this->_values[$key];  
        else  
          throw new Exception("Key $key doesn't exists");  
      }  
      
      function __set($key, $value) {  
        ...  
      }  
    }  
      
    class Person extends DbRecord {  
      protected $_fieldnames = array('foo', 'baz');  
      
      function __construct($db_data) {  
        $this->_values = $db_data;  
      }  
    }  
      
    // Funktionstest  
    echo "<pre>\n";  
    $p = new Person(array('foo' => 'bar', 'baz' => 'qux'));  
    print_r($p);  
    var_dump($p->foo);
    

    Problem ist nun, dass mir get_class_vars(get_class($this)); keine private Members liefert, obwohl der AUFRUF der Methode assign_members() in der abzufragenden Klasse (Person) ist.

    Ja, das scheint an PHPs Implementation von OOP zu liegen. assign_members() wird in der Umgebung der AssignmentClass aufgerufen und von der aus kann es auf die privaten Mitglieder nicht zugreifen. Mit Reflection sollte das aber funktionieren.

    echo "$verabschiedung $name";

    1. Hi,

      danke fuer die Antwort.

      Magische getter, aber vor allem magische setter sind mir garnicht recht.

      Das haette ja zur folge, dass jedes der Felder in $_fieldnames von aussen per getter und setter bearbeitet werden kann - das sollte nicht unbedingt moeglich sein, es verleitet einem das dann zu oft zu benutzen, wodurch die Cross-Klassen-Zugriffe zunehmen, was fuer das Programm nie gut ist ... da wird man schnell denk faul :)

      Reflection is mir ein zu maechtiges Instrument fuer etwas was die Sprache meines Erachtens ohnehin leisten sollte (sie Bemerkung unten).

      Ich habs so gemacht, dass die Unterklassen eine Methode ...

      class Unterklasse extends Oberklasse
      {
       [...]
       // 3 extra Zeilen pro Unterklasse ... aergert mich immer noch, hehe
       protected function get_members()
       {
        return get_class_vars(get_class($this));
       }
       [...]
      }
      ... bekommen, die dann in der Oberklasse aufgerufen wird.

      class Oberklasse
      {
       [...]
       protected function assign_members($data)
       {
        $members = $this->get_members();
        foreach($data as $field_name => $value)
        {
         if(array_key_exists($field_name, $members))
          $this->$field_name = $value;
        }
       }
       [...]
      }

      Komisch ist, dass mir in assign_members() der Aufruf von get_class_vars(get_class($this)); nicht die privaten/protected Members liefert.

      Aber ich kann mit $this->$field_name = $value; diese Werte setzen! Eins der beiden ist dann wohl falsch. Beachtet, es ist eine Vererbungshierarchie, andernfalls ist der Zugriff auf private Members natuerlich zu verbieten, aber in dem Szenario wohl nicht ... Bug?

      Hat jemand noch eine andere Idee?

      Btw, PHP Version is 5.2.0 ... hilft ein Update ..?

      1. echo $begrüßung;

        Magische getter, aber vor allem magische setter sind mir garnicht recht.
        Das haette ja zur folge, dass jedes der Felder in $_fieldnames von aussen per getter und setter bearbeitet werden kann - das sollte nicht unbedingt moeglich sein, es verleitet einem das dann zu oft zu benutzen, wodurch die Cross-Klassen-Zugriffe zunehmen, was fuer das Programm nie gut ist ... da wird man schnell denk faul :)

        Dafür kann ich ja nichts. Mit ähnlicher Argumentation könntest du die Zugriffsmodifizierer verfluchen, da man sie, weil PHP-Code im Quelltext vorliegt, ja mal schnell bei Bedarf umschreiben kann, und sie einen dadurch nicht zu sauberem Stil zwingen.

        echo "$verabschiedung $name";

        1. Ehhhm, wieso denkst du ich wuerde DIR das vorwerfen???

          Klar, du hast mit deinem Argument recht. Das Problem das ich mit den getter/setter sehe ist, dass wenn jemand anderer die Klasse nutzt, dann auch die getter und setter nutzen kann, ohne sich evtl. ein schlaueres Konzept zu ueberlegen.

          Wenn man das mit Bedacht macht, ist es kein Problem.

          Danke jedenfalls fuer deinen Beitrag!

          Trotzalledem, denkst du dass das einen Bugreport wert ist, oder macht das Sinn (der mir verschlossen blieb).

          Danke & Servus

          1. echo $begrüßung;

            Ehhhm, wieso denkst du ich wuerde DIR das vorwerfen???

            Nein, das denke ich nicht. Ich versuchte einfach nur dein Argument zu entkräften.

            Klar, du hast mit deinem Argument recht. Das Problem das ich mit den getter/setter sehe ist, dass wenn jemand anderer die Klasse nutzt, dann auch die getter und setter nutzen kann, ohne sich evtl. ein schlaueres Konzept zu ueberlegen.

            Du schreibst also dieses Projekt nicht (nur) für dich? Nun, wenn es sich um Anwendung in einem geschlossenen Bereich (z.B. in einer Firma) handelt, dann finde ich Regeln zum Programmierstil in einem "Coding Standards"-Dokument besser aufgehoben.
            Wenn du es der Öffentlichkeit zur Verfügung stellst, dann hast du sowieso keine Kontrolle mehr darüber, ob das mit oder ohne schlauem Konzept genutzt wird. Ich würde mich in einem solchen Fall nur darum kümmern, dass der Code meinen Ansprüchen genügt und möglichst keine Sicherheitslücken enthält. Alles andere sehe ich als Sache des Anwenders, dem ich keine Vorschriften zu machen gedenke.

            Trotzalledem, denkst du dass das einen Bugreport wert ist, oder macht das Sinn (der mir verschlossen blieb).

            get_class_vars() ist schon älter als das PHP5-OOP-Konzept. Ich nehme mal an, dass man sich um diese Funktion kaum Gedanken gemacht hat, zumal mit Reflection ein besseres Werkzeug zur Verfügung steht.

            echo "$verabschiedung $name";