auf einen Wert zwischen 128 und 65.000
gesetzt werden.
Die Menge Daten, die in den Variablen gespeichert werden kann,
ist nur durch den verfügbaren Speicher (hierzu zählt auch der ggf.
dynamisch durch Windows belegte Auslagerungsspeicher!) des jeweiligen Rechners
begrenzt. Er kann leicht mehr als 1GB betragen.
Die Arten der Variablen unterscheiden sich in zwei Aspekten: anhand
der "Datentyps" und anhand des "Sichtbarkeit". Daneben haben die Variablen eine
unterschiedliche Lebensdauer, während der sie Speicherplatz belegen.
Datentyp
Visual FoxPro unterscheidet zwischen verschiedenen Datentypen.
Datentypen schränken für Programmiersprachen die Anzahl der Regeln
ein, mit denen die Datenspeicher behandelt werden können. So ist es in
HTML z. B. so, daß dort verwendete Datenspeicher ausschließlich
Zeichenketten (engl. character strings bzw. abgekürzt
strings) VFP unterscheidet hierbei aber sehr penibel:
so kann man z. B. nicht einen Wert vom Datentyp "Datum" mit einem Wert von Datentyp
"Character" (also Zeichenkette) multiplizieren. Allerdings stellt VFP sehr viele
Funktionen zur Verfügung, um Wandlungen aus einem Datentyp in einen anderen
vorzunehmen.
Wie weiß VFP aber nun, von welchem Datentyp der Wert in
einer Variablen ist? In vielen Programmiersprachen muß der Typ explizit
angegeben werden, wenn man eine Variable deklariert. Da die Deklaration in VFP
aber nicht nötig (bzw. sogar nicht einmal möglich) ist, wird in VFP
der Datentyp lediglich durch den Wert selbst, der in der Variablen abgelegt
wird, definiert. Da VFP bei der Zuweisung von Werten ebenfalls implizit die
Deklaration der Variablen übernimmt (s. o.), bestimmt also die Zuweisung
eines Strings, daß der Typ der Variablen vom Typ "Character" ist. Nach
den Anweisungen Test1 = "ABC" und
Test2 = 123 beinhaltet die Variable Test1 einen Wert von Typ Zeichenkette,
die Variable Test2 einen numerischen Wert.
Der Datentyp von Variablen läßt sich in VFP mit Hilfe
der Funktion vartype(<Varname> ).
Diese Funktion liefert einen Buchstaben zurück, der den Datentyp der Variablen
angibt, dabei steht
Buchstabe |
für |
C |
Character (Zeichenkette) |
N |
Numeric (Numerischer Wert; auch float, double, und integer) |
Y |
Currency (Währung) |
D |
Date (Datum) |
T |
DateTime (Datum und Uhrzeit) |
L |
Logical (logisch WAHR oder FALSCH) |
O |
Object (Referenz auf ein Objekt) |
U |
Undefined (undefiniert, also Abfrage eines Variablennamens, der nicht
existiert) |
Durch die implizite Deklaration des Datentyps mit Hilfe der Zuweisung
ist es auch möglich, den Datentyp einer Variablen durch Neuzuweisung eines
anderen Wertes zu ändern. Die im Beispiel oben genannten Variable Test2
hat also nach der Anweisung Test2 = "DEF" nicht
mehr den Datentyp "numeric", sondern den Datentyp "character".
Datentypen in VFP 7.0
Die genannte Technik, daß mit Hilfe
Sichtbarkeit
Variablen sind wie gesagt, Datenspeicher in Programmen. Da aber
eine komplette Applikation aus vielen Programmen, Unter- und Teilprogrammen
besteht, die nicht immer direkt miteinander zu tun haben, müssen bzw. sollten
die Variablen, die in einer Routine benutzt werden, nicht unbedingt in einer
anderen Routine sichtbar sein. Hier kann nun mit der Angabe der Sichtbarkeit
von Variablen eingegriffen werden. Die Sichtbarkeit (engl.
'visibility' oder 'scope') von Variablen bestimmt, in welchen Programmteilen
der belegte Speicherplatz nutzbar ist. Nutzbar heißt hier übrigens,
daß die Variablen sowohl lesbar als auch beschreibbar sind. Das Anlegen
von Variablen, die in anderen Programmteilen nur lesbar sind, ist nicht möglich.
Zur Unterscheidung der Sichtbarkeit kann man Variablen in VFP
mit drei Schlüsselworten deklarieren: public, private
und local. Legt man Variablen ohne ausdrückliche
Deklaration der Sichtbarkeit wie oben genannt an, so erstellt VFP die Variable
als private. Diese Schlüsselworte werden der Nennung des eigentlichen Variablennamens
vorangestellt. dabei ist es möglich, gleich mehrere Variablen au einmal
zu deklarieren, deren Namen werden dann mit Kommas voneinander getrennt. Beispiele:
public Test1
private Test2
local Test3, Test4, Test5
Bei der Deklaration der Variable als public oder als local - jedoch
nicht bei der Deklaration als private - erhalten
diese Variablen direkt einen Inhalt zugewiesen. Dieser steht dann auf .F. (logisch
falsch) damit ist gleichzeitig der erste Datentyp der Variable als "L" festgelegt.
Public
Eine Variable als public zu deklarieren führt dazu, daß
diese Variable danach im gesamten Programmcode in allen Aufrufstufen sichtbar
ist, man spricht hier auch von globalen Variablen. Da eine solche Variable von
allen weiteren Programmen verwendet werden kann, kann deren Inhalt und auch
deren Datentyp auch in Programmen verändert werden, die dafür eigentlich
nicht gedacht sind. Außerdem gibt es bei global vorhandenen Variablen
keinen "Eigentümer", also keinen Programmteil, zu dem die Variable direkt
gehört. Somit kann an keinem Programmteil entschieden werden, ob die Variable
noch benötigt wird und sie wird somit niemals aus dem Speicher gelöscht.
Insofern sollte die Verwendung von public-Variablen nur sehr eingeschränkt
geschehen.
Private
Wird eine Variable als private deklariert, so kann sie von dem
Programm bzw. der Routine genutzt werden, in der sie erzeugt wurde und ist ebenfalls
sichtbar in allen Programmen, die von dort aus aufgerufen werden. Nachdem die
Routine beendet wird, löscht VFP alle Variablen, die darin als private
deklariert wurden, automatisch aus dem Speicher. Die Deklaration von Variablen
als private hat ebenso wie die Deklaration als public den Nachteil, daß
aufgerufene Programme deren Inhalt verändern können, ohne daß
dies in dem aufrufenden Programm gewünscht ist. Insbesondere bei tiefer
geschachtelten Programmen kann dies problematisch sein, dadie aufgerufenen Programme
einen immer größeren Speicherbereich "nutzen" können.
Local
Die Deklaration von Variablen als local bedeutet, daß die
Werte in diesen Variablen nur von dem Anweisungen gesehen und verändert
werden können, die im gleichen Programm stehen. Diese Variablen sind nicht
sichtbar von Programmen, die aufgerufen wurden. Mit dieser Deklaration kann
also verhindert werden, daß (womöglich von fremden Programmierern
erstellter) Programmcode Daten ändert, für die dieser nicht zuständig
ist. Nach dem Ende des aufgerufenen Programms sind die lokalen Variablen im
aufrufenden Programm natürlich wieder ohne Einschränkungen nutzbar.
Ähnlich wie die privaten Variablen löscht VFP die als local deklarierten
aber nach dem Ende der Prozedur, in der sie erzeugt wurden.
Umdeklaration der Sichtbarkeit
In VFP ist eine Umdeklaration der Sichtbarkeit von Variablen möglich.
Dies geht jedoch nur von public nach private und umgekehrt sowie von private
nach local und umgekehrt. Eine Variable, die einmal als local oder public deklariert
war, kann aber nicht in die andere Form deklariert werden, selbst wenn sie zwischendurch
"private" war.
Löschen von Variablen
Neben dem Erzeugen von Variablen hat der Programmierer bei VFP
aber auch die Möglichkeit, diese wieder aus dem Speicher zu löschen.
Außer dem Löschen von privat oder lokal deklarierten Variablen, die
VFP automatisch vornimmt, können beliebig deklarierte Variablen über
den Befehl release wieder aus dem Speicher gelöscht
werden. Ähnlich wie die Deklaration können dabei mehrere Variable
angegeben werden. Der Release-Befehl unterstützt aber auch das Löschen
aller Variablen per release all. Sollen dabei auch alle globalen Variablen
gelöscht werden, muß hier ein release all extended verwendet werden.
Zusätzlich zum Schlüsselwort all kann
ein like <Filter> verwendet werden, in dessen
Filterausdruck Wildcards ("*" und "?") für Buchstaben verwendet werden
können.
Übersicht
|
deklariert |
Sichtbarkeit |
Sichtbar nach Ende |
Programm A
ruft Programm B auf |
keine |
Test1 und Test11 nach Ende von Programm B |
- |
Programm B
ruft Programm C auf
kehrt nach A zurück |
publicTest1
privateTest2
local Test3 |
alle sichtbar |
Test1 |
Programm C
ruft Programm D auf
kehrt nach B zurück |
publicTest11
privateTest22
local Test33 |
Test1 und Test11
Test2 und Test22
Test3 nicht sichtbar
Test33 sichtbar |
Test11 |
Programm D
kehrt nach C zurück |
privateTest222
local Test333 |
Test1 und Test11
Test2 und Test22
Test3 und Test33 nicht sichtbar
Test333 sichtbar |
keine |
Übergabe von Daten zwischen Programmen
Per gemeinsam genutzer Variablen
Zur Übergabe von Daten zwischen verschiedenen Programmen
könnte man nun die im Unterprogramm verwendeten Daten im aufrufenden Programm
als private deklarieren und die Variable, in der der zurückzugebende Wert
abgelegt wird, public erzeugen. Wenn man aber aus Gründen der Programmhygiene
am besten auf globale und private Variablen verzichtet, wie kann man dann Daten
zwischen Programmen austauschen? Schließlich will man die Ergebnisse,
die in einem aufgerufenen Programm errechnet wurden, danach im aufrufenden Programm
verwenden und außerdem müssen die Berechnungen in dem Unterprogramm
ggf. auf Daten zurückgreifen, die das aufrufende Programm bereitstellt.
Als Rückgabe und als Parameter
Die Übergabe eines Wertes aus einem Unterprogramm ist relativ
einfach: wie das Ergebnis von FoxPro-Funktionen in Variablen gespeichert werden
kann, z. B. bei der Anweisung DatumHeute = date( ),
kann ein einzelner Datenwert aus einem aufgerufenen Programm per return-Anweisung
zurückgegeben und in einer Variablen gespeichert werden. Dies sieht dann
wie folgt aus:
Test = MeinTest( )
function MeinTest
private Rueckgabewert
* ... Berechnungen hier
return Rueckgabewert
Nach diesem Durchlauf hat die Variable Test den Wert, der in der
Funktion MeinTest berechnet und zurückgegeben wurde. der Vorteil dieser
Vorgehensweise ist, daß die Funktion MeinTest nicht wissen muß,
wie die Variable heißt, in der der berechnete Wert gespeichert wird. Damit
kann sie aus vielen verschiedenen Programmen heraus genutzt werden.
Die Übergabe von Variablen an ein Programm, damit dieses
die dort enthaltenen Daten nutzt, kann statt über in beiden Programmen
sichtbare Variablen mit sogenannten Parametern oder Argumenten geschehen. Bei
der Übergabe von Parametern an ein anderes Programm kann mit den übergebenen
Daten gerechnet werden. Dabei besteht - bei richtiger Nutzung - nicht die Gefahr,
daß die Werte nach Rückkehr in das aufrufende Programm verändert
sind. Außerdem können die Variablen in dem aufgerufenen Programm
einen eignen Namen bekommen. Damit sind die jeweiligen Programmierer weniger
voneinander und vom Einhalten einer gemeinsamen Vereinbarung zur Benennung der
Variablen abhängig.
Im Code muß die Prozedur, die die Parameter erhalten soll,
mit einer entsprechenden Programmanweisung darauf vorbereitet werden. Dies sieht
dann so aus:
function MeinTest
parameter tcTest1, tcTest2
* weiter Code, z.B.
if tcTest1 = ""
...
Das "parameter"-Statement bedeutet hier, daß beim Aufruf
der Funktion MeinTest zwei neue Variablen erzeugt werden, die tcTest1 und tcTest2
heißen. In diesen Variablen speichert VFP die Werte, die von einem aufrufenden
Programm übergeben werden. Die Variablen werden von VFP dabei automatisch
als "private" deklariert. Sie können im weiteren Verlauf des Programms
genutzt werden wie normal "per Hand" deklarierte Variablen. will man die Variablen
als "local" deklariert haben, so ist die "parameter"-Statement durch
lparameter zu ersetzen. Ebenfalls ist seit der Version VFP 6.0 die Deklaration
von lokalen Variablen zu Übernahme von Parametern in der Deklaration der
Funktion selbst möglich, die beiden Deklarationen
function MeinTest
lparameter tcTest1, tcTest2
und
function MeinTest( tcTest1, tcTest2)
sind dabei in ihrer Funktionalität vollkommen identisch.
Die Funktion kann nun in einem aufrufenden Programm mit
Test = MeinTest( lcVar1, lcVar2) aufgerufen werden. Dabei werden die
Werte, die in lcVar1 und lcVar2 stehen, von VFP an die Funktion MeinTest übergeben.
Übergabearten für Parameter
Die Art und Weise, wie die Variablen übergeben werden, kann
dabei unterschiedlich sein: die Variablen können aus lcVar1 und lcVar2
in neue Variablen tcTest1 und tcTest2 kopiert werden oder sie werden nur unter
neuem Namen in der gleichen Speicherstelle belassen. Die Art, sie zu kopieren,
wird von VFP als "by value" (also Übergabe als Wert), die Art, sie unter
anderem Namen aber an der gleichen Stelle im Speicher zu übergeben als
"by reference" (als Referenz) bezeichnet. Welche Art VFP verwendet, hängt
dabei von verschiedenen Faktoren ab:
- der Aufruf: wird die Funktion als Funktion aufgerufen
(Test = MeinTest( lcVar1, lcVar2)),
werden die Variablen per Kopie ("by value") übergeben, wird die Funktion
als Prozedur aufgerufen (do MeinTest with
lcVar1, lcVar2), werden die Variablen durch
die Übergabe "by reference" weiterverwendet;
- die Einstellung von "set udfparms to value| reference"
("UDF" steht für engl.: user defined function, also benutzerdefinierte
Funktion, mithin ein selbst geschriebenes Programm): hiermit kann eingestellt
werden, daß die Parameter bei Aufruf als Funktion ebenfalls als Referenz
übergeben werden sollen. Allerdings betrifft diese Einstellung nur
die Aufrufe als Funktion: beim Aufruf als Prozedur werden die Parameter
immer per Referenz übergeben;
- eine explizite Übergabe: aus Sicht des aufrufenden
Programms kann ausdrücklich die Übergabe als "value" bzw. per
"reference" angewiesen werden. Damit läßt sich auch die Einstellung
von "udfparms" übersteuern. Eine Übergabe als Wert kann mit Hilfe
von Klammern um die Variablen, eine Übergabe per Referenz durch Voranstellen
eines Klammeraffen erzwungen werden. Diese Einstellung gilt dann immer für
genau eine Variable, die beiden Arten können also auch gemischt auftreten.
Im Code sähe das dann so aus: do MeinTest
with ( lcVar1), @lcVar2 bzw.
Test = MeinTest( lcVar1), @lcVar2). In beiden
Fällen wird die erste Variable als Wert, die zweite als Referenz übergeben
und zwar ohne Berücksichtigung von "set udfparms".
Fehlende Parameter
Enthält ein Programm eine "parameter"- bzw. eine "lparameter"-Anweisung,
so werden die damit deklarierten Variablen auf jeden Fall angelegt, egal, ob
tatsächlich ein Wert übergeben wurde oder nicht. Werden für einen
Parameter keine Werte übergeben, wird dies von VFP ohne weitere Klagen
(sprich: Fehlermeldungen) akzeptiert. In diesem Fall enthalten die in der aufgerufenen
Funktion deklarierten Variablen einfach den Wert "logisch falsch"
(.F.). Ob an eine Funktion Parameter übergeben wurden und wenn ja,
wieviele, kann mit den Visual-FoxPro-Funktionen "pcount( )" und parameters(
) abgefragt werden. Diese beiden Funktionen liefern jeweils die Anzahl der zuletzt
übergebenen Parameter, im Fall, daß keine Parameter übergeben
wurden, also schlicht 0. Bei der Arbeitsweise der beiden Funktionen besteht
ein kleiner aber feiner Unterschied: pcount( ) liefert immer die Anzahl der
Parameter, die an die aktuelle Funktion geliefert wurden, parameters( ) hingegen
die Anzahl Parameter, die zuletzt an ein Programm übergeben wurden. Im
Code hätte dies folgende Auswirkungen:
...
do MeinTest with lcVar1, lcVar2
function MeinTest( lcTest1, lcTest2)
?pcount( )gibt "2" aus
do MeinTest2 with lcTest2
?parameters( )gibt "1" aus
?pcount( )gibt nach wie vor "2" aus
Achtung: in VFP ist das Auslassen
von Parametern möglich, indem man einfach eine Anweisung
do MeinTest with , lcVar2 formuliert. Die Funktionen pcount( ) und parameters(
) liefern hier aber trotzdem eine "2" zurück!
Zu viele Parameter
Übergibt man an ein Programm mehr Parameter, als dort deklariert
sind, gibt VFP eine Fehlermeldung (Nummer 94: "Must specify additional parameters")
aus. Bei Angabe von Parametern, die an ein Programm übergeben werden sollen,
wenn dort gar keine Anweisung zur Übernahme von Parametern existiert, wird
die Fehlermeldung 1238 ( "No PARAMETER statement is found") ausgegeben.
Arrays
Deklaration und Zugriff
Arrays ( in der deutschen Dokumentation "Datenfelder" genannt)
sind eine besondere Art von Variablen: sie können mehrere Werte ("Elemente")
beinhalten, die unter einem Namen ansprechbar sind. Zusätzlich zu diesem
Namen muß dann eine sogenannten "Subskriptionsangabe" gemacht werden,
die angibt, das wievielte Element aus dem Array gemeint ist. Arrays müssen
neben der Deklaration der Sichtbarkeit über public, private oder local
als eine Angabe zu ihrer Größe haben Die Anzahl der Elemente in einem
Array ist auf 65.000 begrenzt. Bei der Deklaration des Arrays verfügen
die Befehle von VFP über unterschiedliche Möglichkeiten:
- in den Deklarationen "public" und "local"
ist das Schlüsselwort "array" erlaubt, das die Deklaration
der Arraygröße in einer Zeile erlaubt: public
array gaMeinArray[ 10] bzw. local
array laMeinArray[ 10] erzeugen jeweils ein
Array mit 10 Elementen
- ein Array, das als privat deklariert wird, muß
in einem zweiten Schritt dimensioniert werden:
private paMeinArray
dimension paMeinArray[ 10]
Die Arrayelemente erhalten in jedem Fall zunächst den Wert
logisch falsch (.F.). Nach der Deklaration kann
durch Zugriffe unter Zuhilfenahme der Subskriptnummer ein einzelner Wert gesetzt
oder ausgelesen werden:
laMeinArray[ 2] = date( )
Var = laMeinArray[ 2]
Es lassen sich auch alle die Werte aller Arrayelemente mit einem
Befehl auf einen Wert setzen, indem die Subskriptionsnummer wegelassen wird:
laMeinArray = "". Das funktioniert allerdings
natürlich nur beim Setzen, ein Auslesen eines Arrays ohne Subskript liefert
zwar keinen Fehler, gibt aber immer den Inhalt des ersten Elementes zurück.
Neben den eindimensionalen Arrays, in denen über eine einzelne
Subskriptionsangabe auf einzelne Elemente referenziert werden kann, unterstützt
VFP zweidimensionale Arrays, allerdings keine drei- oder mehrdimensionalen.
Diese zweidimensionalen Arrays kann man sich als Tabelle mit Spalten und Zeilen
vorstellen. Bei solchen zweidimensionalen Arrays müssen immer zwei Subskripte
angegeben werden: das erste für die Anzahl der Zeilen, das zweite für
die Anzahl der Spalten: local array laMeinArray[ 5, 3]
erstellt also ein lokales Array mit fünf Zeilen und drei Spalten.
Arrays lassen sich zu jeder Zeit in ihrer Größe verändern,
indem einfach eine neue Dimensionierung angegeben wird
(dimension laMeinArray[ 6, 4]). Bei einer Verkleinerung des Arrays werden
dann einfach die überzähligen Elemente am Ende des Arrays abgeschnitten,
bei einer Vergrößerung werden neue Elemente angelegt und erhalten
automatisch den Vorgabewert .F..
In einem Array lassen sich in den einzelnen Elementen Werte von
jeweils unterschiedlichem Datentyp speichern, ein Array ist also nicht darauf
beschränkt, nur Zeichenketten oder nur numerische Werte zu beinhalten,
sondern es können alle Datentypen in einem einzigen Array vorkommen. Mit
Hilfe dieser Mechanismen kann man nun also temporäre Tabellen im Speicher
aufbauen, die innerhalb einer Zeile Strings, numerische Werte und auch Objektreferenzen
enthalten. Innerhalb eines solchen Arrays kann nun mit einer einzigen VFP-Funktion,
nämlich "ascan( )" nach einzelnen Elementen gesucht werden, ohne daß
hier Rücksicht auf den Rdatentyp genommen werden muß.
Übergabe von Arrays als Parameter
Arrays lassen sich auch als Parameter an selbst geschriebene Funktionen
weitergeben. Allerdings ist hier eine Besonderheit zu beachten: Arrays können
nicht per Value übergeben werden. Da das Array aus vielen Werten besteht,
müßte hier ja angegeben werden, welche Werte alle übergeben
werden sollen. Eine solche Syntax wird von VFP aber nicht unterstützt Übergibt
man einer Funktion im Aufruf nur den Namen des Arrays, also
MeinTest( laTest), so interpretiert VFP dies als Übergabe des ersten
Elementes aus dem Array. In der korrespondierenden Parameterdeklaration der
Funktion "MeinTest" kommt also nur der Wert an, der in laTest[ 1] enthalten
ist. Um nun das Array als Ganzes zu übergeben, muß die Übergabe
"per Referenz" erfolgen. In dem Aufruf der Funktion ist also dem Arraynamen
ein "@" voranzustellen, der Aufruf sähe
also so aus: MeinTest( @laTest). Dabei ist nun
zu beachten, daß im Parameter der Funktion MeinTest genau die selben (und
nicht etwa die gleichen) Werte enthalten sind, die die aufrufende Routine in
das Array gesteckt hat. Ändert man nun einen Wert in dem Array, so wirkt
sich diese Änderung auch in dem aufrufenden Programm aus.
Funktionen zu Arrays
Arrays werden in VFP in vielen Funktionen unterstützt bzw.
genutzt. So liefern viele Befehle und Funktionen ihre Ergebnisse in Arrys zurück,
die dabei sogar "on the fly" erzeugt werden können. So können z. B.
die Ergebnisse eines SQL Select mit der Klause "into array" direkt in einem
Array abgelegt werden. Die Funktion Adir( <ArrayName> ) legt
die Informationen der Dateien eines Verzeichnisses mit Dateinamen, -größe,
Attributen und Änderungsdatum im übergebenen Array ab und man kann
Strukturinformationen einer Tabelle, die Inhalte eines Datensatzes einer Tabelle
etc. direkt in Arrays zwischenspeichern. Hinzu kommen viele Funktionen, die
das Durchsuchen oder Sortieren von Arrays erlauben oder Funktionen, die einzelne
Elemente, Zeilen oder Spalten in der Mitte eines Arrays löschen oder einfügen
können.
Objekte und Properties
Objekte in Visual FoxPro bieten neben den Deklarationen von "public",
"private" oder "local"-Variablen eine weitere Möglichkeit, den Zugriff
auf Speicherstellen einzugrenzen. Dabei kann jedes Objekt selbst in einer Variablen
gespeichert werden. Innerhalb des Objektes gibt es nun aber weitere Speicherplätze,
ähnlich den Arrayelementen, von denen auch beliebig viele über einen
Variablennamen angesprochen werden können. Solche Speicherplätze,
die innerhalb eines Objektes liegen, werden als Properties bzw. Eigenschaften
bezeichnet. Der Unterschied zwischen Arrayelementen und den Properties ist allerdings,
daß die Arrayelemeten nur über eine numerische Referenz innerhalb
der Arrayvariablen angesprochen werden können, die Eigenschaften eines
Objektes aber eigene Namen haben. Syntax von VFP für den Zugriff auf die
Properties ist die Trennung des Propertynamen vom Objektnamen durch einen Punkt.
Ist also über den Variablennamen loTestObjekt ein Objekt ansprechbar, das
eine Eigenschaft "Name" hat, so kann der Wert dieser Eigenschaft mit der Anweisung
?loTestObjekt.Name erfragt werden. Ebenso ist natürlich das Setzen eines
neuen Wertes möglich: loTestObjekt.Name = "Neuer Name". Zu jedem Objekt
können beliebig viele Eigenschaften hinzugefügt werden. Interessant
hieran ist, daß diese Eigenschaften wiederum die gleichen Merkmale haben,
wie die Variablen von VFP. Dies betrifft die möglichen Datentypen und die
Namenskonventionen, und sogar das Erstellen eines Properties als Array ist möglich.
Namenskonventionen
Variablen und Properties können mit Namen versehen werden,
die maximal 128 Zeichen lang sind. Diese Namen dürfen nur Buchstaben, Ziffern
und Unterstriche enthalten, andere Sonderzeichen sind nicht erlaubt. Die Namen
müssen mit einem Buchstaben oder einem Unterstrich anfangen. Deutsche Umlaute
sind hierbei erlaubt.
Visual FoxPro unterscheidet beim Zugriff auf Variablen ebenso
wie bei der Nutzung von eingebauten oder selbst geschriebenen Befehlen oder
Funktionen nicht zwischen Groß- und Kleinschreibung. Nach Ablauf der vier
Anweisungen
DatumHeute = "heute"
DATUMHEUE = 0101200
datumheute = {01.01.2000}
DATUMheute = date( )
existiert also nur eine einzige Variable, die dann das aktuelle
Tagesdatum beinhaltet. Es hat sich allerdings bewährt, zur Erhöhung
der Lesbarkeit die Variablennamen in gemischter Schreibweise zu schreiben. Dabei
wird jeweils der Anfang eines neuen Wortes groß, der Rest klein geschrieben.
Bei der Deklaration von Variablen sollte man sich zudem an die
sogenannte "ungarische Notation" halten . Diese Notation sieht vor den eigentlichen
Namen der Variablen (z. B. DatumHeute) einen Präfix vor, in dem die Sichtbarkeit
der Variablen und deren Datentyp genannt wird. Hierfür werden folgende
Buchstaben verwendet:
Sichtbarkeit |
Beschreibung |
Beispiel |
l |
local |
lnZähler |
p |
private (default) |
pnStatus |
g |
public (global) |
gnVorherigerSatz |
t |
Parameter |
tnSatznummer |
Für die Nennung des Typs werden folgende Buchstaben verwendet (vgl. a.
Datentyp):
Typ |
Beschreibung |
Beispiel |
a |
Array |
aMonate |
c |
Character |
cNachName |
y |
Currency |
yAktuellerWert |
d |
Date |
dGeburtstag |
t |
Datetime |
tLetzteÄnderung |
b |
Double |
bWert |
f |
Float |
fZinsSatz |
l |
Logical |
lStatus |
n |
Numeric |
nZähler |
o |
Object |
oPerson |
u |
Unknown |
uRückgabeWert |
Mögliche Konflikte
Variablen und Tabellenfelder
Für die Benennung von Variablen gelten in VFP die gleichen
Vorschriften, wie für die Benennung von Feldern einer Tabelle. Insofern
läßt sich innerhalb der Codezeile lcTest =
Name nicht unterscheiden, ob der Inhalt der Variablen lcTest nachher
dem Inhalt der Variablen Name entspricht oder ob hier der Inhalt des Feldes
NAME aus einer Tabelle gelesen wurde. Da auch VFP dies in diesem Beispiel nicht
unterscheiden kann, geht das Programm hier davon aus, daß mit "Name" der
Inhalt eines Tabellenfeldes gemeint war, wenn die Tabelle in aktuellen Arbeitsbereich
ein solches Feld enthält. Dabei ist VFP völlig egal, der Nennung von
"Name" kein Alias vorangestellt ist.
Dieser Vorrang für die Datenfelder kann nur umgangen werden,
indem einer Variablen, so sie denn mit "Name" gemeint sein soll, ein "m." vorangestellt
wird. Da der Buchstabe "M" nicht als Alias für eine Tabelle erlaubt ist,
ist damit die Eindeutigkeit für VFP wiederhergestellt:
lcTest = m.Name. Allerdings ist es hier erstaunlicherweise so, daß
VFP die Voranstellung des "m." mit einer (wenn auch nur geringfügig) längeren
Ausführungszeit quittiert. Es kann also zu Erreichung einer maximalen Performance
sinnvoll sein, die Unterscheidung von Feldern und Variablen nur anhand der verschiedenen
Namenskonventionen zu machen. Schließlich dürfte eine Variable nach
den oben genannten Konventionen eigentlich nur z. B. "lcName" heißen,
Da aber die Deklaration von "local" bzw. "private" oder "public" für Tabellenfelder
nicht sinnvoll ist, kann das entsprechende Feld einer Tabelle dann nur "cName"
heißen, wodurch eine Verwechslung ausgeschlossen ist.
Vergleiche liefern falsche Ergebnisse
Je nach Einstellung von "SET EXACT" führt VFP Vergleiche
von Variablen unterschiedlich aus. In folgender Codesequenz liefert der Vergleich
zum Schluß tatsächlich ein ".T."!
lcTest1 = "ABC"
lcTest2 = "A"
?lcTest1 = lcTest2
Woran liegt das nun wieder? Die beiden Strings sind doch nun definitiv
nicht gleich. Zusätzlich verworren wird das Ganze, wenn man den Ausdruck
umdreht. Die Frage
liefert wiederum ein ".F."! Hier muß man schlicht wissen,
daß VFP bei der Einstellung "OFF" von "EXACT" die beiden Strings nur so
lange vergleicht, bis das Ende des zweiten Strings erreicht wurde. Wurde bis
hierher kein Unterschied festgestellt, sind die beiden Strings für VFP
gleich. Will man sicher sein, daß VFP wirklich darauf untersucht, daß
beide Strings hundertprozentig gleich sind, so ist die Anweisung "= =" zu verwenden.
Die liefert ohne Rücksicht auf die Einstellung von "set exact" das Ergebnis
eines vollständigen Vergleichs, nämlich in der letzten Zeile von:
set exact off
lcTest1 = "ABC"
lcTest2 = "A"
?lcTest1 == lcTest2
tatsächlich ein ".F.".
Das gleiche Verhalten von VFP finden wir, wenn wir innerhalb von
Feldern in einer Tabelle suchen. In einer Tabelle sei ein Feld mit Namen "Name"
und der Länge 10 enthalten. Dazu ist ein Index auf das Feld "Name" aktiv:
dann liefert die folgende Sequenz ein ".T.", obwohl der
String in lcTest1 um 7 Zeichen kürzer ist, als der Inhalt des Datenfeldes:
lcTest1 = "ABC" ?seek( lcTest1)
Dies gilt übrigens auch, wenn "set exact" auf "ON" steht.
Konstanten
Die Speicherung von Daten in Variablen hat neben dem Anteil, daß
hier variable Werte in den Speicherstellen abgespeichert werden können,
den Vorteil, daß diese Werte über einen speziellen Namen angesprochen
werden können. Die Verwendung von solchen "sprechenden" Namen ist auch
für Daten wünschbar, die sich nicht während der Laufzeit eines
Programmes verändern. Solche Daten können als sogenannte Konstanten
definiert werden. Wofür aber nun solche Konstanten definieren, schließlich
kann man Daten, die sich nicht mehr ändern ja auch direkt in den Code schreiben?
Ein Vorteil von Konstanten ist, daß ihnen Namen gegeben werden können.
Besonders praktisch ist dies, wenn in einem Programm mehrspaltige Arrays (s.d.)
verwendet werden sollen. Innerhalb dieser Arrays müssen die Spalten ja
immer über Nummern angesprochen werden, z. B. laMeinArray[
6, 4]. Bei dieser Programmierung muß man sich innerhalb des Programms
immer daran erinnern, was nun in Spalte 4 des Arrays steht, aber woher kann
man dies wissen? Bliebe nur, alle Zugriffe auf das Array mit Kommentaren zu
versehen, oder eben Konstanten zu verwenden. Angenommen, wir haben in dem Array
laMeinArray mit Hilfe der Funktion adir( ) die Informationen eines Directories
abgelegt. Dann stünde in der vierten Spalte des Arrays die Zeit der letzten
Speicherung der Datei. Um sich nicht immer daran erinnern zu müssen, daß
die Zeit nicht in der fünften Spalte steht, kann man eine Konstante mit
dem Namen k_nSpeicherzeit anlegen und dieser den Wert 4 geben. Damit sähe
die genannte Anweisung dann so aus: laMeinArray[ 6, k_nSpeicherzeit]. Das ist
schon einigermaßen sprechend, und braucht nicht mehr kommentiert zu werden.
Wie funktionieren nun Konstanten? Innerhalb eines Programmes können
zur Zuweisung von Werten zu solchen Namen beliebige "defines" liegen. Diese
Definitionen haben folgendes Format: #define k_nSpeicherzeit 4. Trifft der Compiler
nun auf eine solche Anweisung, speichert er diese Zuweisung intern, ersetzt
in den folgenden Codezeilen den Namen mit dem zugewiesenen Wert und compiliert
diesen. Für das compilierte Programm macht diese Zuweisung also keine Unterschied
und kostet demnach auch keine Laufzeit. Vor allem bei der Definition von numerischen
Konstanten ergibt sich ein spezieller Vorteil, wenn sich die Struktur eines
Arrays doch einmal ändert, also eine Spalte hinzugefügt wird und sich
alle anderen nach hinten verschieben: hier genügt eine einfache Anpassung
der Wertzuweisungen der Konstanten und ein anschließendes Neucompilieren,
ohne daß man manuelle Änderungen an den Codestellen machen muß.
Aber auch bei größeren Änderungen, für die man die zugehörigen
Codestellen suchen muß, ist es besser, zum Ändern aller betroffener
Codestellen nach einem aussagekräftigen Namen zu suchen und nicht nach
einer einzelnen Ziffer, denn damit wird die Anzahl der gefundenen Stellen drastisch
eingeschränkt.
Es lassen sich beliebig viele Konstanten definieren. Diese Definitionen
lassen sich in Dateien zusammenfassen, die normalerweise mit der Endung ".H"
(für ("Header") versehen werden. Diese Dateien und damit alle enthaltenen
Konstantendefinitionen können dann per "#include"-Anweisung in eine Programmdatei
eingebunden werden. Eine solche Datei wird mit VFP bereits mitgeliefert. In
dieser sind bereits einige Konstanten für Arrays oder andere VFP-Funktionen
definiert. Die Progrmme werden mit Einsatz dieser Konstanten erheblich lesbarer,
denn wissen Sie, was die Funktion messagebox( "Nachricht", 52) ausgibt? Mit
Hilfe von Konstanten ergibt sich hier ein messagebox( "Nachricht", MB_YESNO
+ MB_ICONEXCLAMATION), also eine Nachricht mit Ja- und Nein-Knopf und einem
Ausrufezeichen als Icon und das ist doch schon viel lesbarer oder?
In diesem Sinne: |
|
Referenzen
Jim Booth: "A Day in the Life of a Variable", FoxTalk July 1999
Online-Hilfe zu Visual FoxPro