|
1 |
nachdem Holger heute den Bug eingestellt hat den ich schon lange befürchtet
|
|
2 |
habe, bin ich heute mal die globalen Variablen angegangen. Das ganze ist über
|
|
3 |
die Jahre leider recht komfus geworden, deshalb hier ne Erklärung, die
|
|
4 |
hoffentlich sowas in Zukunft vermeidet.
|
|
5 |
|
|
6 |
|
|
7 |
Wie sehen globale Variablen in Perl aus?
|
|
8 |
----------------------------------------
|
|
9 |
|
|
10 |
Globale Variablen liegen in einem speziellen namespace namens "main", der von
|
|
11 |
überall erreichbar ist. Darüber hinaus sind bareword globs global und die
|
|
12 |
meisten speziellen Variablen sind... speziell.
|
|
13 |
|
|
14 |
Daraus ergeben sich folgende Formen:
|
|
15 |
|
|
16 |
$main::form - expliziter namespace main
|
|
17 |
$::form - impliziter namespace main
|
|
18 |
open FILE, "file.txt" - FILE ist global
|
|
19 |
$_ - speziell.
|
|
20 |
|
|
21 |
(Ja, da fehlen noch ein paar Sachen, ich weiß)
|
|
22 |
|
|
23 |
Im Gegensatz zu PHP gibt es kein Schlüsselwort wir "global" mit dem man
|
|
24 |
importieren kann, my, our und local machen was anderes.
|
|
25 |
|
|
26 |
my $form - lexikalische Variable, gültig bis zum Ende des scopes
|
|
27 |
our $form - $form referenziert ab hier $PACKAGE::form.
|
|
28 |
local $form - Alle Änderungen an $form werden am Ende des scopes zurückgesetzt
|
|
29 |
|
|
30 |
Warum ist das ein Problem?
|
|
31 |
--------------------------
|
|
32 |
|
|
33 |
Das erste Problem ist FCGI.
|
|
34 |
|
|
35 |
sql-ledger hat fast alles im globalen namespace abgelegt, und erwartet, dass es
|
|
36 |
da auch wiederzufinden ist. Unter FCGI müssen diese Sachen auch wieder
|
|
37 |
aufgeräumt werden, damit sie nicht in den nächsten Request kommen. Einige
|
|
38 |
Sachen wiederum sollen nicht gelöscht werden, wie zum Beispiel
|
|
39 |
Datenbankverbindungen, weil die ne Ewigkeit zum initialisieren brauchen.
|
|
40 |
|
|
41 |
Das zweite Problem ist strict.
|
|
42 |
|
|
43 |
Unter strict werden alle Variablen die nicht explizit mit Package, my oder our
|
|
44 |
angegeben werden als Tippfehler angemarkert, was einen vor so mancher Stunde
|
|
45 |
suchen nach einem Bug erspart. Da globale Variablen aber implizit mit Package
|
|
46 |
angegeben werden, werden die nicht geprüft, und ein Tippfehler da fällt
|
|
47 |
niemandem auf.
|
|
48 |
|
|
49 |
Kanonische globale Variablen
|
|
50 |
----------------------------
|
|
51 |
|
|
52 |
Um dieses Problem im Griff zu halten gibt es einige wenige globale Variablen,
|
|
53 |
die kanonisch sind, und alles andere sollte anderweitig umhergereicht werden.
|
|
54 |
|
|
55 |
Diese Variablen sind im Moment die folgenden neun:
|
|
56 |
|
|
57 |
$::form
|
|
58 |
%::myconfig
|
|
59 |
$::locale
|
|
60 |
$::lxdebug
|
|
61 |
$::auth
|
|
62 |
$::lx_office_conf
|
|
63 |
$::instance_conf
|
|
64 |
$::dispatcher
|
|
65 |
$::request
|
|
66 |
|
|
67 |
Damit diese nicht als Müllhalde misbrauch werden, im Folgenden eine kurze
|
|
68 |
Erläuterung was man von denn erwarten kann.
|
|
69 |
|
|
70 |
|
|
71 |
$::form
|
|
72 |
|
|
73 |
- Ist ein Objekt der Klasse "Form"
|
|
74 |
- Wird nach jedem Request gelöscht
|
|
75 |
- Muss auch in Tests und Konsolenscripts vorhanden sein.
|
|
76 |
- Enthält am Anfang eines Requests die Requestparameter vom User
|
|
77 |
- Kann zwar intern über Requestgrenzen ein Datenbankhandle cachen, das wird
|
|
78 |
aber momentan absichtlich zerstört
|
|
79 |
|
|
80 |
$::form wurde unter sql ledger als Gottobjekt für alles misbraucht. Sämtliche alten
|
|
81 |
Funktionen unter SL/ mutieren $::form, das heißt, alles was einem lieb ist,
|
|
82 |
sollte man vor einem Aufruf von zum Beispiel IS->retrieve_customer in Sicherheit bringen.
|
|
83 |
|
|
84 |
Das Objekt der Klasse Form hat leider im Moment noch viele zentrale Funktionen
|
|
85 |
Gdie vom internen Zustand abhängen, deshalb bitte nie einfach zerstören oder
|
|
86 |
überschreiben. Es geht ziemlich sicher etwas kaputt.
|
|
87 |
|
|
88 |
$::form ist gleichzeitig der Standard Scope in den Template::Toolkit Templates
|
|
89 |
ausserhalb der Controller, der Ausdruck [% var %] greift auf $::form->{var} zu.
|
|
90 |
Unter Controllern ist der Standard Scope anders, da lautet der Zugriff [%
|
|
91 |
FORM.var %]. In Druckvorlagen sind normale Variablen ebenfall im $::form Scope,
|
|
92 |
d.h. <%var%> zeigt auf $::form->{var}. Innerhalb von Schleifen
|
|
93 |
wird $::form->{TEMPLATE_ARRAYS}{var}[$index] bevorzugt wenn vorhanden.
|
|
94 |
|
|
95 |
|
|
96 |
%::myconfig
|
|
97 |
|
|
98 |
- Das einzige Hash unter den globalen Variablen
|
|
99 |
- Wird spätestens benötigt wenn auf die Datenbank zugegriffen wird
|
|
100 |
- Wird bei jedem Request neu erstellt.
|
|
101 |
- Enthält die Userdaten des aktuellen Logins
|
|
102 |
- Sollte nicht ohne Filterung irgendwo gedumpt werden oder extern serialisiert
|
|
103 |
werden, weil da auch der Datenbankzugriff für diesen user drinsteht.
|
|
104 |
- Enthält unter anderem Listenbegrenzung vclimit, Datumsformat dateformat und
|
|
105 |
Nummernformat numberformat
|
|
106 |
- Enthält Datenbankzugriffinformationen
|
|
107 |
|
|
108 |
%::myconfig ist im Moment der Ersatz für ein Userobjekt. Die meisten Funktionen,
|
|
109 |
die etwas anhand des aktuellen Users entscheiden müssen befragen %::myconfig.
|
|
110 |
|
|
111 |
|
|
112 |
$::locale
|
|
113 |
|
|
114 |
- Objekt der Klasse "Locale"
|
|
115 |
- Wird pro Request erstellt
|
|
116 |
- Muss auch für Tests und Scripte immer verfügbar sein.
|
|
117 |
- Cached intern über Requestgrenzen hinweg benutzte Locales
|
|
118 |
|
|
119 |
Lokalisierung für den aktuellen User. Alle Übersetzungen, Zahlen- und
|
|
120 |
Datumsformatierungen laufen über dieses Objekt.
|
|
121 |
|
|
122 |
|
|
123 |
$::lxdebug
|
|
124 |
|
|
125 |
- Objekt der Klasse "LXDebug"
|
|
126 |
- Wird global gecached
|
|
127 |
- Muss immer verfügbar sein, in nahezu allen Funktionen
|
|
128 |
|
|
129 |
$::lxdebug stellt Debuggingfunktionen bereit, wie "enter_sub" und "leave_sub",
|
|
130 |
mit denen in den alten Modulen ein brauchbares Tracing gebaut ist, "log_time",
|
|
131 |
mit der man die Wallclockzeit seit Requeststart loggen kann, und "message" und
|
|
132 |
"dump" mit denen man flott Informationen ins Log packen kann.
|
|
133 |
|
|
134 |
|
|
135 |
$::auth
|
|
136 |
|
|
137 |
- Objekt der Klasse "SL::Auth"
|
|
138 |
- Wird global gecached
|
|
139 |
- Hat eine permanente DB Verbindung zur Authdatenbank
|
|
140 |
- Wird nach jedem Request resettet.
|
|
141 |
|
|
142 |
$::auth stellt Funktionen bereit um die Rechte des aktuellen Users abzufragen.
|
|
143 |
Obwohl diese Informationen vom aktuellen User abhängen wird das Objekt aus
|
|
144 |
Geschwindigkeitsgründen nur einmal angelegt und dann nach jedem Request kurz
|
|
145 |
resettet.
|
|
146 |
|
|
147 |
|
|
148 |
$::lx_office_conf
|
|
149 |
|
|
150 |
- Objekt der Klasse "SL::LxOfficeConf"
|
|
151 |
- Global gecached
|
|
152 |
- Repräsentation der config/lx_office.conf[.default] Dateien
|
|
153 |
|
|
154 |
Globale Konfiguration.
|
|
155 |
|
|
156 |
Configdateien werden zum Start gelesen, und nicht mehr angefasst. Es ist
|
|
157 |
derzeit nicht geplant, dass das Programm die Konfiguration ändern kann oder
|
|
158 |
sollte.
|
|
159 |
|
|
160 |
Der Konfigurationskey
|
|
161 |
|
|
162 |
[Debug]
|
|
163 |
|
|
164 |
file = /tmp/lxoffice_debug_log.txt
|
|
165 |
|
|
166 |
ist im Programm als $::lx_office_conf->{Debug}{file} erreichbar.
|
|
167 |
|
|
168 |
Warnung: Zugriff auf die Konfiguration erfolgt im Moment über Hashkeys, sind
|
|
169 |
also nicht gegen Tippfehler abgesichert.
|
|
170 |
|
|
171 |
|
|
172 |
$::instance_conf
|
|
173 |
|
|
174 |
- Objekt der Klasse "SL::InstanceConfiguration"
|
|
175 |
- wird pro Request neu erstellt.
|
|
176 |
|
|
177 |
Funktioniert wie $::lx_office_conf, speichert aber Daten die von der Instanz
|
|
178 |
abhängig sind. Eine Instanz ist hier eine Mandantendatenbank. Prominentestes
|
|
179 |
Datum ist "eur", die Information ob Bilanz oder Einnahmenüberschussrechnung
|
|
180 |
gemacht wird.
|
|
181 |
|
|
182 |
|
|
183 |
|
|
184 |
$::dispatcher
|
|
185 |
|
|
186 |
- Objekt der Klasse "SL::Dispatcher"
|
|
187 |
- wird pro Serverprozess erstellt.
|
|
188 |
- enthält Informationen über die technische Verbindung zum Server
|
|
189 |
|
|
190 |
Der dritte Punkt ist auch der einzige Grund warum das Objekt global gespeichert
|
|
191 |
wird. Wird vermutlich irgendwann in einem anderen Objekt untergebracht.
|
|
192 |
|
|
193 |
|
|
194 |
|
|
195 |
$::request
|
|
196 |
|
|
197 |
- Hashref
|
|
198 |
- Wird pro Request neu initialisiert.
|
|
199 |
- Keine Unterstruktur garantiert.
|
|
200 |
|
|
201 |
$::request ist ein generischer Platz um Daten "für den aktuellen Request"
|
|
202 |
abzulegen. Sollte nicht für action at a distance benutzt werden, sondern um
|
|
203 |
lokales memoizing zu ermöglichen, das garantiert am Ende des Requests zerstört
|
|
204 |
wird.
|
|
205 |
|
|
206 |
Vieles von dem was im moment in $::form liegt sollte eigentlich hier liegen.
|
|
207 |
Die groben Differentialkriterien sind:
|
|
208 |
|
|
209 |
- Kommt es vom User, und soll unverändert wieder an den User?
|
|
210 |
=> $::form, steht da eh schon
|
|
211 |
|
|
212 |
- Sind es Daten aus der Datenbank, die nur bis zum Ende des Requests gebraucht werden?
|
|
213 |
=> $::request
|
|
214 |
|
|
215 |
- Muss ich von anderen Teilen des Programms lesend drauf zugreifen?
|
|
216 |
=> $::request, aber Zugriff über Wrappermethode
|
$::request als globale Variable eingeführt.