Az 1997.ben bevezetett 5.0-s verziójától a Clipper nyelvben is volt lehetőség hibakezelése. Be lett vezetve az ERROR hibaobjektum osztály, amely nem valódi osztály, csak egy adattípus feldekorálva, melyek segítségével objektum jellegűen lehet kezelni az ilyen típusú változókat.
Az ERROR fontosabb adattagjai:
Args: | a hibához köthető adatok egy tömbben. | ||||||||
Description: | a leírása emberek számára feldolgozható módon (a hiba szöveges leírása). | ||||||||
FileName: | a hibához köthető fájl neve. | ||||||||
GenCode | a hiba leírása számítógép által feldolgozható módon (Clipper hibakód). | ||||||||
Operation: | a hibát kiváltó művelet. | ||||||||
Severity: | a hiba súlyossága. Lehetséges értékei és jelentésük:
|
||||||||
SubCode: | operációs rendszer hibakódja. |
A Clipper hibakezelésnek a működése a mai programnyelek TRY-CATCH hibakezeléséhez hasonló felépítésű (nincs a FINALLY-val párhuzamba állítható nyelvi elem). Ez több nyelvi elem kombinálásával alakul ki:
A hibakezelés felépítése:
BEGIN SEQUENCE // egyéb CLIPPER utasítások ... BREAK [kifejezés] //Ez történhet egy alprogramban is ... // egyéb CLIPPER utasítások [RECOVER [USING oError] //hibakezelő utasítások] END SEQUENCE>
A BEGIN SEQUENCE - [RECOVER] - END SEQUENCE utasításblokk konstrukcióban a RECOVER opcionális. Ha a szekvencia hibakezelés céllal van létrehozva, akkor kell, ha hiba elnyelési céllal, akkor nem kell.
Amennyiben a program egy utasításblokkban egy BREAK utasításhoz ért, akkor attól függően, hogy van-e RECOVER az utasításblokk hátralevő részében vagy nem, ha van, akkor a program vezérlése az adott utasításblokk RECOVER utasítástól folytatódik, ha nem, akkor az utasításblokk végétől. Ha a BREAK mögött meg van adva egy kifejezés, akkor a RECOVER USING használatával az egy változóban átvehető. Ha a RECOVER-re nem egy BREAK utasításról érkezett a vezérlés, akkor a RECOVER-nél a vezérlés az END SEQUENCE utasításra kerül, a köztük levő utasításokat figyelmen kívül hagyva.
A rendszerben tárolva van egy dedikált hibakezelő kódblokk, amire rákerült a vezérlés minden fellépő hiba esetén.
Ez paraméterben megkapja a fellépett hibát leíró ERROR objektumot. Ezt a kódblokkot az ERROBLOCK függvénnyel lehet lekérni
illetve beállítani is ezzel lehet új értéket. Ennek a szignatúrája:
ERRORBLOCK([bNewErrorBlock]) -> bLastErrorBlock
Hibakezeléshez be lehetett ennek a hibakezelő kódblokknak az értékét állítani a {|x| BREAK(x)} kódblokkra. Ekkor hiba esetén a kapott hiba objektummal azonnal elugrik a legközelebbi RECOVER-re vagy END SEQUENCE-re. Emiatt a viselkedés miatt fontos a hibakezelésnél a RECOVER használata: amennyiben nincsen RECOVER adva egy utasítás blokkban, akkor a BREAK hatására az END SEQUENCE-re ugik és a kiváltott hiba elnyelődik.
Az alapértelmezett hibakezelési kódblokk hatására a SEQUENCE nyelvi konstrukcióval elérhető volt, hogy a feladatot megvalósító programrész a BEGIN SEQUENCE és RECOVER közé kerüljön, a hibakezelés a RECOVER és az END SEQUENCE közé.
Az ERRORBLOCK függvénnyel át lehet állítani a hibakezelést tetszőleges kódblokkra. Megtehető, hogy akár egy saját függvényünk fusson le (pl. a hiba kinaplózása miatt, majd utána mi adjuk ki a BREAK utasítást).
Mivel a hibakezelő kódblokk a fentiek miatt bármire lehet állítva, ha speciálisan az alapértelmezett hibakezelő kódblokk
funkcionalitását szeretnénk garantáltan használni, akkor szükséges beállítani azt. Azért, hogy csak az aktuális függvényre
és az onnan hívottakra érvényesüljön ez a módosításunk, le kell menteni a BEGIN SEQUENCE előtt, majd az END SEQUENCE után visszaállítani
a korábbi (általunk nem ismert funkcionalitású) hibakezelő kódblokkot. Ezzel elérhető, hogy egy függvényhívás ilyen szempontból a környezet
viselkedését ne változtassa meg.
Ez a gyakorlatban így néz ki:
local bPrevErrorBlock //A kívánt hibakezelés beállítása, korábbi lementése bPrevErrorBlock := ERRORBLOCK({|oError| BREAK(oError)}) BEGIN SEQUENCE //Ide kerül a futtatott kód RECOVER USING oError //Ide kerül a hibakezelés END SEQUENCE //Korábbi hibakezelés visszaállítása ERRORBLOCK(bPrevErrorBlock)
Bár nem deklarálhatunk kivételeket, ennek ellenére lehetoségünk van a hibák kezelésére. Ennek eszköze: ON ERROR és ON READERROR parancsok. Hiba jelentkezése esetén a paraméterként megadott utasítás vagy alprogram kerül végrehajtásra.
Ez paraméterként megkaphatja
A hibakezelõ függvénybõl RETRY-al visszatérve, a hibát kiváltó parancsot újra megpróbálja végrehajtani. (Használhatjuk például adatbekérésnél ellenõrzésre.)
A program futása során akárhányszor használhatjuk az ON ERROR és ON READERROR parancsokat, mindig az éppen aktuális hibakezelõ fog lefutni. (Paraméter nélkül írva az alapértelmezés lép életbe, azaz hiba esetén a program futása megszakad.)
Az ON READERROR segítségével az I/O mûveletekben közben fellépõ hibákat kezelhetjük.
A 8.0-ás verziótól lehetõségünk van a kivételkezelés alkalmazására.
TRY [ tryCommands ] [ CATCH [ TO VarName ] [ WHEN lExpression ] [ catchCommands ] ] [ THROW [ eUserExpression ] ] [ EXIT ] [ FINALLY [ finallyCommands ] ] ENDTRY
A kivételkezelésre a fenti szerkezetet alkalmazhatjuk.
A TRY blokkban elhelyezett sorok által kiváltott kivételeket a CATCH kifejezés segítségével kezelhetjük le.
A THROW utasítás segítségével válthatunk ki kivételt. A parancs alkalmazható a CATCH blokkban is.
A blokk azonnali befejezését elérhetjük az EXIT utasítással, ami mindhárom részben alkalmazható.
A TRY és a CATCH részben kiadott EXIT utasítás hatására a vezérlés a FINALLY blokkhoz kerül.
Ha a FINALLY-ban használjuk, akkor az ENDTRY-hoz jutunk.
A FINALLY blokkban elhelyezett sorok minden esetben végrehajtódnak, kivéve a CANCEL és QUITalkalmazása esetén.
A kivételobjektum autómatikusan létrejön hiba esetén.
CATCH mûködése
WHEN után megadható feltétel teljesülése esetén a megadott változó egy a kivételobjektumra
mutató referenciát fog tartalmazni.
Ezután a CATCH blokkban található utasítások hajtódnak végre. Ebben a blokkban a referencián keresztûl felhasználhatjuk a
kivételobjektumban tárolt összes információt.
THROW mûködése
A Kivételt mi is kiválthatjuk a THROW utasítás segítségével, aminek paraméterként egy
EXCEPTION osztályból, vagy leszármazottjából példányosított kivételobjektumot kell megadnunk.
A THROW által kiváltott kivételek ErrorNo attribútumát a rendszer utómatikusan 2071-re állítja,
ami a felhasználó által dobott kivételek száma.
Példa: