kivitendo/doc/20111013_globale_variablen.txt @ 5494f687
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
|
|||
- Hashref
|
|||
- 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
|