kivitendo/doc/20111013_globale_variablen.txt @ 1ed28475
772f08d0 | Sven Schöling | nachdem Holger heute den Bug eingestellt hat den ich schon lange befürchtet
|
||
habe, bin ich heute mal die globalen Variablen angegangen. Das ganze ist über
|
||||
die Jahre leider recht komfus geworden, deshalb hier ne Erklärung, die
|
||||
hoffentlich sowas in Zukunft vermeidet.
|
||||
Wie sehen globale Variablen in Perl aus?
|
||||
----------------------------------------
|
||||
Globale Variablen liegen in einem speziellen namespace namens "main", der von
|
||||
überall erreichbar ist. Darüber hinaus sind bareword globs global und die
|
||||
meisten speziellen Variablen sind... speziell.
|
||||
Daraus ergeben sich folgende Formen:
|
||||
$main::form - expliziter namespace main
|
||||
$::form - impliziter namespace main
|
||||
open FILE, "file.txt" - FILE ist global
|
||||
$_ - speziell.
|
||||
(Ja, da fehlen noch ein paar Sachen, ich weiß)
|
||||
Im Gegensatz zu PHP gibt es kein Schlüsselwort wir "global" mit dem man
|
||||
importieren kann, my, our und local machen was anderes.
|
||||
my $form - lexikalische Variable, gültig bis zum Ende des scopes
|
||||
our $form - $form referenziert ab hier $PACKAGE::form.
|
||||
local $form - Alle Änderungen an $form werden am Ende des scopes zurückgesetzt
|
||||
Warum ist das ein Problem?
|
||||
--------------------------
|
||||
Das erste Problem ist FCGI.
|
||||
sql-ledger hat fast alles im globalen namespace abgelegt, und erwartet, dass es
|
||||
da auch wiederzufinden ist. Unter FCGI müssen diese Sachen auch wieder
|
||||
aufgeräumt werden, damit sie nicht in den nächsten Request kommen. Einige
|
||||
Sachen wiederum sollen nicht gelöscht werden, wie zum Beispiel
|
||||
Datenbankverbindungen, weil die ne Ewigkeit zum initialisieren brauchen.
|
||||
Das zweite Problem ist strict.
|
||||
Unter strict werden alle Variablen die nicht explizit mit Package, my oder our
|
||||
angegeben werden als Tippfehler angemarkert, was einen vor so mancher Stunde
|
||||
suchen nach einem Bug erspart. Da globale Variablen aber implizit mit Package
|
||||
angegeben werden, werden die nicht geprüft, und ein Tippfehler da fällt
|
||||
niemandem auf.
|
||||
Kanonische globale Variablen
|
||||
----------------------------
|
||||
Um dieses Problem im Griff zu halten gibt es einige wenige globale Variablen,
|
||||
die kanonisch sind, und alles andere sollte anderweitig umhergereicht werden.
|
||||
Diese Variablen sind im Moment die folgenden neun:
|
||||
$::form
|
||||
%::myconfig
|
||||
$::locale
|
||||
$::lxdebug
|
||||
$::auth
|
||||
$::lx_office_conf
|
||||
$::instance_conf
|
||||
$::dispatcher
|
||||
$::request
|
||||
Damit diese nicht als Müllhalde misbrauch werden, im Folgenden eine kurze
|
||||
Erläuterung was man von denn erwarten kann.
|
||||
$::form
|
||||
- Ist ein Objekt der Klasse "Form"
|
||||
- Wird nach jedem Request gelöscht
|
||||
- Muss auch in Tests und Konsolenscripts vorhanden sein.
|
||||
- Enthält am Anfang eines Requests die Requestparameter vom User
|
||||
- Kann zwar intern über Requestgrenzen ein Datenbankhandle cachen, das wird
|
||||
aber momentan absichtlich zerstört
|
||||
$::form wurde unter sql ledger als Gottobjekt für alles misbraucht. Sämtliche alten
|
||||
Funktionen unter SL/ mutieren $::form, das heißt, alles was einem lieb ist,
|
||||
sollte man vor einem Aufruf von zum Beispiel IS->retrieve_customer in Sicherheit bringen.
|
||||
Das Objekt der Klasse Form hat leider im Moment noch viele zentrale Funktionen
|
||||
Gdie vom internen Zustand abhängen, deshalb bitte nie einfach zerstören oder
|
||||
überschreiben. Es geht ziemlich sicher etwas kaputt.
|
||||
$::form ist gleichzeitig der Standard Scope in den Template::Toolkit Templates
|
||||
ausserhalb der Controller, der Ausdruck [% var %] greift auf $::form->{var} zu.
|
||||
Unter Controllern ist der Standard Scope anders, da lautet der Zugriff [%
|
||||
FORM.var %]. In Druckvorlagen sind normale Variablen ebenfall im $::form Scope,
|
||||
d.h. <%var%> zeigt auf $::form->{var}. Innerhalb von Schleifen
|
||||
wird $::form->{TEMPLATE_ARRAYS}{var}[$index] bevorzugt wenn vorhanden.
|
||||
%::myconfig
|
||||
- Das einzige Hash unter den globalen Variablen
|
||||
- Wird spätestens benötigt wenn auf die Datenbank zugegriffen wird
|
||||
- Wird bei jedem Request neu erstellt.
|
||||
- Enthält die Userdaten des aktuellen Logins
|
||||
- Sollte nicht ohne Filterung irgendwo gedumpt werden oder extern serialisiert
|
||||
werden, weil da auch der Datenbankzugriff für diesen user drinsteht.
|
||||
- Enthält unter anderem Listenbegrenzung vclimit, Datumsformat dateformat und
|
||||
Nummernformat numberformat
|
||||
- Enthält Datenbankzugriffinformationen
|
||||
%::myconfig ist im Moment der Ersatz für ein Userobjekt. Die meisten Funktionen,
|
||||
die etwas anhand des aktuellen Users entscheiden müssen befragen %::myconfig.
|
||||
$::locale
|
||||
- Objekt der Klasse "Locale"
|
||||
- Wird pro Request erstellt
|
||||
- Muss auch für Tests und Scripte immer verfügbar sein.
|
||||
- Cached intern über Requestgrenzen hinweg benutzte Locales
|
||||
Lokalisierung für den aktuellen User. Alle Übersetzungen, Zahlen- und
|
||||
Datumsformatierungen laufen über dieses Objekt.
|
||||
$::lxdebug
|
||||
- Objekt der Klasse "LXDebug"
|
||||
- Wird global gecached
|
||||
- Muss immer verfügbar sein, in nahezu allen Funktionen
|
||||
$::lxdebug stellt Debuggingfunktionen bereit, wie "enter_sub" und "leave_sub",
|
||||
mit denen in den alten Modulen ein brauchbares Tracing gebaut ist, "log_time",
|
||||
mit der man die Wallclockzeit seit Requeststart loggen kann, und "message" und
|
||||
"dump" mit denen man flott Informationen ins Log packen kann.
|
||||
$::auth
|
||||
- Objekt der Klasse "SL::Auth"
|
||||
- Wird global gecached
|
||||
- Hat eine permanente DB Verbindung zur Authdatenbank
|
||||
- Wird nach jedem Request resettet.
|
||||
$::auth stellt Funktionen bereit um die Rechte des aktuellen Users abzufragen.
|
||||
Obwohl diese Informationen vom aktuellen User abhängen wird das Objekt aus
|
||||
Geschwindigkeitsgründen nur einmal angelegt und dann nach jedem Request kurz
|
||||
resettet.
|
||||
$::lx_office_conf
|
||||
- Objekt der Klasse "SL::LxOfficeConf"
|
||||
- Global gecached
|
||||
- Repräsentation der config/lx_office.conf[.default] Dateien
|
||||
Globale Konfiguration.
|
||||
Configdateien werden zum Start gelesen, und nicht mehr angefasst. Es ist
|
||||
derzeit nicht geplant, dass das Programm die Konfiguration ändern kann oder
|
||||
sollte.
|
||||
Der Konfigurationskey
|
||||
[Debug]
|
||||
file = /tmp/lxoffice_debug_log.txt
|
||||
ist im Programm als $::lx_office_conf->{Debug}{file} erreichbar.
|
||||
Warnung: Zugriff auf die Konfiguration erfolgt im Moment über Hashkeys, sind
|
||||
also nicht gegen Tippfehler abgesichert.
|
||||
$::instance_conf
|
||||
- Objekt der Klasse "SL::InstanceConfiguration"
|
||||
- wird pro Request neu erstellt.
|
||||
Funktioniert wie $::lx_office_conf, speichert aber Daten die von der Instanz
|
||||
abhängig sind. Eine Instanz ist hier eine Mandantendatenbank. Prominentestes
|
||||
Datum ist "eur", die Information ob Bilanz oder Einnahmenüberschussrechnung
|
||||
gemacht wird.
|
||||
$::dispatcher
|
||||
- Objekt der Klasse "SL::Dispatcher"
|
||||
- wird pro Serverprozess erstellt.
|
||||
- enthält Informationen über die technische Verbindung zum Server
|
||||
Der dritte Punkt ist auch der einzige Grund warum das Objekt global gespeichert
|
||||
wird. Wird vermutlich irgendwann in einem anderen Objekt untergebracht.
|
||||
$::request
|
||||
3b9a5301 | Sven Schöling | - Hashref (evtl später Objekt)
|
||
772f08d0 | Sven Schöling | - Wird pro Request neu initialisiert.
|
||
- Keine Unterstruktur garantiert.
|
||||
$::request ist ein generischer Platz um Daten "für den aktuellen Request"
|
||||
abzulegen. Sollte nicht für action at a distance benutzt werden, sondern um
|
||||
lokales memoizing zu ermöglichen, das garantiert am Ende des Requests zerstört
|
||||
wird.
|
||||
Vieles von dem was im moment in $::form liegt sollte eigentlich hier liegen.
|
||||
Die groben Differentialkriterien sind:
|
||||
- Kommt es vom User, und soll unverändert wieder an den User?
|
||||
=> $::form, steht da eh schon
|
||||
- Sind es Daten aus der Datenbank, die nur bis zum Ende des Requests gebraucht werden?
|
||||
=> $::request
|
||||
- Muss ich von anderen Teilen des Programms lesend drauf zugreifen?
|
||||
=> $::request, aber Zugriff über Wrappermethode
|
||||
3b9a5301 | Sven Schöling | |||
Ehemalige globale Variablen
|
||||
---------------------------
|
||||
Die folgenden Variablen waren einmal im Programm, und wurden entfernt.
|
||||
$::cgi
|
||||
- war nötig, weil cookie Methoden nicht als Klassenfunktionen funktionieren
|
||||
- Aufruf als Klasse erzeugt Dummyobjekt was im Klassennamespace gehalten wird
|
||||
und über Requestgrenzen leaked
|
||||
- liegt jetzt unter $::request->{cgi}
|
||||
$::all_units
|
||||
- war nötig, weil einige Funktionen in Schleifen zum Teil ein paar hundert mal
|
||||
pro Request eine Liste der Einheiten brauchen, und die als Parameter durch
|
||||
einen Riesenstack von Funktionen geschleift werden müssten.
|
||||
- Liegt jetzt unter $::request->{cache}{all_units}
|
||||
- Wird nur in AM->retrieve_all_units gesetzt oder gelesen.
|
||||
%::called_subs
|
||||
- wurde benutzt um callsub deep recursions abzufangen.
|
||||
- Wurde entfernt, weil callsub nur einen Bruchteil der möglichen Rekursioenen
|
||||
darstellt, und da nie welche auftreten.
|
||||
- komplette recursion protection wurde entfernt.
|