|
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 (evtl später Objekt)
|
|
- 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
|
|
|
|
|
|
|
|
|
|
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.
|