PHP Blogger

Startseite Schreib mir ne Mail! RSS Abo Webnews

Eure Meinung: Sichtbarkeit von Variablen

So, nachdem ich einige Wochen unterwegs war, Timi mit dem Blog alleine gelassen habe und mal eine Runde Abstand vom programmieren hatte, komme ich zurück, aktualisiere meine PHP Installation auf die neueste Version, starte mein Projekt und: BUMM, nichts geht mehr. Meine Sessions scheinen Variablen zu verlieren, Objekte sind nicht mehr komplett, bzw. leer. Was ist da los? Habe ich mein Projekt mit einem Riesenbug stehen lassen und bin in Urlaub gefahren?

Also gut, Suche beginnt.

Session scheint ok zu sein. Nur die Objekte sind irgendwie verstümmelt. Aber der Reihe nach. Ich programmiere seit einer Weile in PHP5 und versuche auch eine sinnvolle Klassenstruktur zu wahren. Jedenfalls habe ich sowas wie die Mutter aller Objekte, von denen sich sämtliche Klassen ableiten. In diesem Objekt habe ich eine Funktion __sleep, was eine Magic Function ist, die beim schreiben in die Session von PHP aufgerufen wird, um im Objekt aufzuräumen und meine CFG Referenz, in der unter anderem DB Connection etc. liegt nicht zu serialisieren.

public function __sleep()
{
  $vars = array_keys(get_object_vars($this));
  $cfg = array_search('cfg', $vars);
  unset($vars[$cfg]);
  return $vars;
}

Nach einigen Tests fand ich dann, dass die Funktion get_object_vars nicht mehr wie vorher alle Variablen des Objektes liefert, sondern nur noch alles was public deklariert ist. Dies wird aber nicht weiter erwähnt im Changelog, genauso wenig in der Doku auf der Funktionsseite. Jedenfalls ist mein Verständnis von Objekten dahingehend, dass ich als ein Kindobjekt diese __sleep Funktion aufrufe, dass ich gefälligst alle Variablen bekommen soll, die dieses Objekt hat und nicht nur die, die vom Scope des Parent, also meiner abstrakten Klasse sichtbaren, bekomme.

Jedenfalls habe ich schön in der Bug Datenbank recherchiert, bevor ich diesen Code verschickt habe.

Nun meine Frage: Was ist für euch das erwartete Verhalten von dem verlinkten Code? Habe ich das falsch verstanden und werde jetzt brav meine ganzen Variablen alle nur als protected deklarieren, damit ich eine generelle __sleep Funktion haben kann, bzw. per Reflection meine gesetzen Klassenvariablen bekommen kann?

  • MisterWong
  • del.icio.us
  • Technorati
  • Digg
  • Slashdot
  • YahooMyWeb
  • Furl
  • Ma.gnolia
  • Spurl
  • Netscape
  • StumbleUpon
  • MyShare
  • blogmarks

timi meint dazu:

21. Oktober 2007 um 11:09

Hi Phil,

schön das Du wieder an Board bist… Also ich sehe die Sache folgendermaßen:

1. get_object_vars ist eine globale Funktion und keine Memberfunktion von this. Dementsprechend ist es richtig, dass

2. nur externen Zugriff auf public oder protected Variablen hat, die von Nicht-Memberfunktionen zugänglich sind (denn private deklarierte Variablen sind Klasseninternen Memberfunktionen vorbehalten), deshalb ist es

3. kein Bug, sondern ein Feature… ;) und somit

4. ist die Fehlermeldung bei PHP hinfällig *zwinker*

Eine Lösung ist es aber keinesfalls, alles auf protected umzustellen - das ist ja auch nicht im Sinne des Erfinders.

Da __sleep bewusst eine Memberfunktion Deiner zu serialisierenden Objekte ist, könntest Du für jedes zu serialisierende Objekt explizit die __sleep Funktion implementieren. Das wäre vom Programmierhandwerk her gesehen das Beste.

Vielleicht hat ja jemand ne Idee, wie man es automatisieren könnte, weil es ne Menge Aufwand bedeutet, Deine Klassen umzustellen…

phil meint dazu:

21. Oktober 2007 um 11:28

Ich denke mal, dass es wesentlich mehr Aufwand ist diese __sleep Funktion in jedem Member Objekt zu haben?! Du kennst ja so ein bisschen meine Programmierstil…

Hab jedenfalls erstmal die Variablen auf protected geändert. Jetzt läuft der Laden erstmal wieder, bis ich einen neuen Weg überlege, die gesetzten Variablen meines Objektes auszulesen :)

aleks meint dazu:

21. Oktober 2007 um 11:40

wenn es unbedingt sein muss - mit der reflection api sollte das doch gehen:

http://php.net/manual/en/language.oop5.reflection.php

aber warum soll es überhaupt in *jedem* objekt eine referenz auf ein objekt mit konfigurationsdaten wie der datenbankverbindung geben? (und warum dann plötzlich nicht mehr?)

phil meint dazu:

21. Oktober 2007 um 11:52

Also, es hat nicht JEDES Objekt eine Referenz auf die DB, aber ich habe ein Konfigurationsobjekt, das ich bei Bedarf in dem entsprechenden Objekt registrieren kann, damit es eben DB anfragen etc. ausführen kann. Wenn ich so ein Objekt dann in der Session übertragen will, dann soll dieses Konf-Objekt eben nicht mit in die Session, weil die DB Connection eben auf jeden Fall wieder erneuert werden muss. Also wird automatisch diese Sleep Funktion gecallt. Dafür ist die in PHP eingeführt worden.

Und ich denke nicht, dass es besonders performant ist, wenn ich nach jedem Pageload, in dem ein oder viele Datenobjekte geladen wurden diese per Reflection Reverse Engineere…

Frank meint dazu:

21. Oktober 2007 um 19:39

Hiho,
ich bin frpoh, dass PHP endlich deutlich mehr in die Richtung geht, die JAVA schon vor Jahren eingeschlagen hat. Das Verhalten ist imho absolut korrekt.

Siehe dazu auch die Doku unter:
http://de.php.net/manual/de/language.oop5.visibility.php

Gruß
_Frank

timi meint dazu:

21. Oktober 2007 um 22:22

Aleks hat Recht. Wie wärs, wenn Du Dir die DB Klasse per Singleton holst, wenn Du sie benötigst, dann muss sie nicht als Klassenmember eingebettet sein?

RSS für Kommentare zu diesem Artikel · TrackBack URI

Schreib Deine Meinung