ugrás a tartalomhoz

Hibakezelés (try-catch, throw new Exception) -konstrukotrban/destruktorban

H.Z. v2 · 2011. Jún. 11. (Szo), 10.19
Kezdek kiakadni a PHP-re, de nagyon:

Egy külön file-ból betöltött osztály konstruktorában felfedezett hibát szeretnék jelezni egy throw new Exception-nel az objektumot létrehozni akaró programrésznek.
Egyszerűen nem törődik vele, fut tovább, mintha mi sem történt volna...

class DB {
protected $l;
  function __construct(){
    ...
    try {
     $this->l=new Logger("logdir/log.txt");
     $this->l->put("uzenet");
    } catch (Exception $e){
      ---hibaüzenet megjelenítése---
    }
}

class Logger {
  protected $logfile;
  function __construct($fil){ $this->logfile=$fil; }

  private function writeLog($uz){
    if(!$f=fopen($this->logfile,"a")){ throw new Exception("Hiba"); }
    ...
  }
  function put($uz){
    $this->writeLog($uz);
  }
}

Kb. így néz ki a problémás rész (remélem, nem írtam el semmit - az eredeti kódot kiherélni kissé macerásnak tűnik)
A DB konstruktorában a try-catch blokk nem képes elkapni a Loggerben kiváltott Exception-t.

Az tiszta, hogy átírhatom a programot úgy, hogy a konstruktorokban ne legyen hibakezelést igénylő művelet, de ez megint egy olyan dolog, hogy akkor minek a konstruktor, ha nem automatizálhatom a tennivalókat, rajta keresztül?
Másik variáció, hogy a hibakezelést igénylő műveletek hibaága egy die-ban kell, hogy végződjön, ami megintcsak nem tetszik, de kényszermegoldásként lehet, hogy ezt fogom használni.



+1, a fentitől független, de már a tapétát kaparom, annyira nem értem:
<?php
  if(!defined('XXXX')){ exit; }
  /*...
több soros, kikommentezett szakasz
*/
?>

Ennyi a file tartalma és azt bírja mondani, hogy "syntax error, unexpected T_CONSTANT_ENCAPSED_STRING in"
Ezek után töröltem a file-t, újra beírtam a kommentek nélkül, most jó...
Ciki, hogy eredetileg úgy hoztam létre, hogy egy működő php file-t lemásoltam, kikommenteztem a tartalmát és elé írtam a fenti if... sort.
 
1

try/catch

Poetro · 2011. Jún. 11. (Szo), 16.07
Throw-t ne rakj konstruktorba. Ennyi az egész. Arra nemgondoltál, hogy nem jól kommentezted ki a kódot? A kódszínezônek visítani kellet volna, valamint megnézhetted volna a hibásnak ítélt sort is.
2

Köszi, ettől tartottam.

H.Z. v2 · 2011. Jún. 11. (Szo), 16.51
Köszi, ettől tartottam. Sajnos nem csak én rakok throw-t a konstruktorba, hanem pl. egy PDO művelet is képes ilyen aljasságra (amit egy konstruktorból hívott metódusban létrehozott objektum egyik metódusának hívásakor indítok :))) ) - először ennél akadtam el, úgy jutottam végül a fenti kódhoz, hogy ott ugyanúgy nem megy ez a játék.
Akkor tényleg marad amit írtam, hogy vagy die v. nem a konstruktorban csinálom a hibalehetőséggel bíró műveleteket.


A másik: vi-t használok, nem látszott rajta, hogy gond lenne a file-lal. A végén, kínomban már töröltem is a kód maradékát, csak az if(!defined... maradt benne, de úgy is pofázott. Ezzel kellőképp felbosszantott, töröltem, újra beírtam, most megy. Kapjabe... :-)
(ilyenkor bezzeg nem teszem el törlés előtt a git-be, nehogy vissza tudjam hozni... :-( )
5

Szvsz semmi gond nincs a

bh · 2011. Jún. 12. (V), 21.21
Szvsz semmi gond nincs a konstruktorban levo hibakezelessel. Elegansan lehet kezelni a benne fellepo problemakat (pl parameter gondok). Mivel a konstruktor peldanyosit es nincs visszateresi erteke igy logikus a kivetelkezeles hasznalata benne. Bar fontos odafigyelni, hogy takaritson fel maga utan, amennyiben esetleg dob vmit, mert ebben az esetben a destruktora mar nem fog lefutni.
8

Így van, egyszerűen elnéztem

H.Z. v2 · 2011. Jún. 13. (H), 06.52
Így van, egyszerűen elnéztem a dolgot. :-)
Viszont furcsa, hogy senkinek sem tűnt fel: amire panaszkodtam, az egy try-catch blokkban lévő exception, aminek ebben a formában működnie kellene. Gondot a kezeletlen exception okozna azzal, hogy megszakítja a konstruktor futását->nem tud korrekt módon felépülni az objektum, de ilyesmiről szó sem volt. (és szerencsére működik is)
10

Miért?

saxus · 2011. Jún. 13. (H), 10.10
Throw-t ne rakj konstruktorba.


Ezzel nem értek egyet. Miért ne lehetne kivételt dobni konstruktorból? Van mondjuk egy fájlt beolvasó konstruktorunk. Eléggé nonszensz lenne, ha nem dobhatnánk onnan kivételt.

A fenti kódban ami inkább kifogásolható az a kivétel lekezelése. Ugyan az egyetemen azt tanítják, hogy minden kivételt le kell kezelni - amivel egy cseppet sem akarok vitatkozni - azonban azt nem tanítják meg, hogy hol. Pl. az adatbázis-kezelő rétegnek nem biztos, hogy kellene foglalkoznia üzenetek megjelenítésével.
13

A nagy könyv azt írja, hogy

H.Z. v2 · 2011. Jún. 13. (H), 18.45
A nagy könyv azt írja, hogy nem szabad megszakítani a konstruktort, mert... Valami olyat írtak, hogy félkész objektum jön létre, ha nem tud lefutni a konstruktor. Ezt nem igazán értem, mondhatni hülyeségnek tartom, hiszen ha félbeszakítom a konstruktort, akkor az lenne a logikus, hogy a futtató nem hozza létre az objektumot, oszt jónapot.

A fenti kód csak egy az eredeti alapján összetákolt példa volt, mert azt hittem, hogy a konstruktorban lévő catch nem tudja elkapni a try blokkban létrehozott és felhasznált objektum által kiváltott exception-t. Utóbb kiderült, hogy ez nem igaz, nem onnan jöttek a hibaüzenetek.

Az üzenet megjelenítéséről csak annyit: ez az egész arról szólt volna, hogy az adatbáziskezelővel kapcsolatot tartó osztály logolja a saját működését és ehhez egy már elkészült, log író osztály egy példányát használtam fel.
(hangsúlyozom: tanulom a PHP-t és az objektum orientált "tervezést", az egész pusztán arra kellett, hogy később vissza tudjam keresni, melyik programrész mit művelt, merre járt)
16

Keress másik könyvet :)

saxus · 2011. Jún. 14. (K), 09.49
Ez így nem igaz másrészt keveredést érzek benne. Egyrészt ha a konstruktorban hiba történik, akkor márpedig ugyanúgy meg kell szakítani. Nyilvánvalóan, ha olyan erőforrást foglalunk le, amelyet a nyelv (PHP esetén ilyen viszonylag kevés van) nem szabadít fel magától, akkor azt az esetet le kell kezelni ilyenkor konstruktorból és tovább dobni a kivételt. (Megjegyzés: ilyenkor tud szép lenni, amikor a takarító kód dob még kivételt és ha nem tudunk arról, hogy volt korábban kivétel, mehet a pislogás.)

Ez a félkész objektum meg csalóka. A legtöbb nyelvben mire a konstruktorok kezdenek futni, nyelv szempontjából maga az objektum létezik, hiszen le van neki foglalva a memória és be van neki állítva a típusa. Logikailag nekünk ugyan még nincs kész, hiszen nincsen a mi értelmezésünk szerint alapállapotba állítva. Viszont előfordulhat olyan eset, hogy ez nem teljesíthető, ilyenkor dobunk kivételt. Ilyenkor logikailag valóban nem lesz "kész" az osztály, azonban a kivétellel egyértelműen jeleztük, hogy ez egy selejt osztály, nem biztos, hogy használni kellene, sőt inkább el kellene takarítani (ha a nyelv nem tenné meg automatikusan).
17

Öt perce bányásztam elő a

H.Z. v2 · 2011. Jún. 14. (K), 10.19
Öt perce bányásztam elő a "gyári" php doksit, mert engem is zavart, hogy konstruktort nem lehet félbeszakítani. Természetesen hülyeséget írtak ott, ahonnan úgymond idéztem.
Destruktorban nem illik, mert azonnal Fatányéros... izé... fatal error lesz az eredmény, de a konstruktorra nincs megkötés. (sajnos/szerencsére nem találom az eredeti forrásomat :) )

Félkész objektum: ettől kezdve természetesen az is hülyeség volt. Egyébként ha abortálom a konstruktort, akkor nem ad értéket a "new" mellett, az = bal oldalán álló változónak, ergo nem is jön létre az objektum.
3

Hát ez a no comment kategória...

H.Z. v2 · 2011. Jún. 11. (Szo), 23.12
A konstruktorban lévő hibakezeléssel semmi gond nincs. Az üzenet, amit az apache logjában találtam, a destruktorból jött.
Onnan is maceráltam volna a logot és akkor jött a kezeletlen és kezelhetetlen hiba. Hogy miért, arról csak sejtéseim vannak: destruktorban már nem lehet számítani az objektum által korábban létrehozott változókra/objektumokra... (bár így sem teljesen tiszta, mert a hibaüzenet szerint nem éri el a használandó logfile-t, holott maga a file elérhető, hiszen pár sorral korábban még írt bele és a log file nevét sem felejtette még el)
4

destruktorba se

blacksonic · 2011. Jún. 12. (V), 12.49
ha lehet destruktorba se dobj kivételt
6

Konstruktorral (talan, de itt

bh · 2011. Jún. 12. (V), 21.33
Konstruktorral (talan, de itt is eloallhat olyan eset amikor erdemes lehet) ellentetben destruktorban nem szerencses a kivetel dobas, legabbis ha pl az objektum felszabaditasat nem teszed egy try-c blokkba (try{unset($obj)...} (Ez mondjuk mar kevesbe szep megoldas). A hiba akkor jon elo, ha destruktorban dobsz vmit es nem kezeled, mert ugye a destruktor a szkript vegeztevel lefut es nincs ki kezelje a kivetelt (ezen mar a sajat kivetelkezelod sem segit, igy a hibazasi lehetoseg is nagy).
7

Destruktorral jobb, ha nem

inf · 2011. Jún. 12. (V), 21.38
Destruktorral jobb, ha nem foglalkozol :-)
9

Átalában. De én most tanulom

H.Z. v2 · 2011. Jún. 13. (H), 06.53
Átalában.
De én most tanulom a PHP-t, kipróbálok mindent, még azt is, amit elvileg nem lenne szabad, mert csak olvasással nem lehet tanulni. ;-)
11

Jó persze. Annyit kell tudni

inf · 2011. Jún. 13. (H), 11.03
Jó persze. Annyit kell tudni róla, hogy amikor a destruktor lefut, akkor már a rendszer eltakarította az összes kapcsolódó objektumot. Mivel a destruktornak (szerintem) az lenne az értelme, hogy segíts a rendszernek mondjuk adatbázis kapcsolatokat lezárni, ezért tök felesleges foglalkozni vele. Megcsinálja a php magától is. A másik oldala, hogy abból meg végképp káosz van, ha nem elég átlátható, hogy melyik metódus futásakor éppen hogy néz ki a környezet...
12

Keverem a Java-val? Mintha

H.Z. v2 · 2011. Jún. 13. (H), 18.44
Keverem a Java-val?
Mintha azt olvastam volna, hogy a változók, objektumok stb. állapota nem meghatározható, nem azt, hogy el lettek takarítva. (ezt csak a "precizitás" kedvéért... ;-) )
14

Jóvanna :D Majd jöhetsz

inf · 2011. Jún. 14. (K), 04.25
Jóvanna :D Majd jöhetsz hozzánk fát hasogatni, a szőrszállal már megy... :D
15

Ha megfizeted... más munkát

H.Z. v2 · 2011. Jún. 14. (K), 06.05
Ha megfizeted... más munkát úgysem találok.
18

:D :D :D

inf · 2011. Jún. 14. (K), 11.19
:D :D :D
19

Sajnos ennyire nem vicces a

H.Z. v2 · 2011. Jún. 14. (K), 12.13
Sajnos ennyire nem vicces a helyzet... ;-)

Mellesleg: szopatom magam, mint a torkosborz, hogy át tudjam írni a PDO és a PDOStatement execute metódusát, mert az SQL hibákat szeretném Exception-ként viszontlátni, erre... PDO::setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION) és máris minden szép... :D
20

A beépített

inf · 2011. Jún. 14. (K), 12.50
A beépített metódusokat/függvényeket nem érdemes felüldefiniálni php-ben (inkább hegessz fölé egy adaptert), egyébként meg érdemes dokumentációt olvasni néha :D
21

Adapter alatt nem t'om, mit

H.Z. v2 · 2011. Jún. 14. (K), 13.15
Adapter alatt nem t'om, mit értesz. Doksit meg olvasok, csak kissé felületesen. :)
Gyártottam egy osztályt, extends PDO-val, aztán sokáig gondolkodtam, hogy lehetne kulturáltan elérni, hogy pl. a prepare ne PDOStatement objektumot adjon vissza, hanem egy olyat, amit én írtam és a PDOStatement leszármazottja. Mire ma megtaláltam, hogy a setAttribute-tal el tudom érni, addigra azt is felfedeztem, hogy Exception-t is lehet kérni, ha valami hiba történik a mysql-ben. :D
22

Adapter pattern

solkprog · 2011. Jún. 14. (K), 13.42
23

Hát csinálsz egy

inf · 2011. Jún. 14. (K), 13.50
Hát csinálsz egy PDOProvider-t, ami módosított PDO objektumokat ad (vagy PDO adaptereket), meg csinálsz egy PDOStatementFactory-t, ami saját típusú statementeket ad. Kb ennyi. Nem nehéz. Az adapter gyakorlatilag annyi, hogy azon keresztül példányosítod a PDO-t meg azon keresztül hívod meg minden egyes metódusát. Így remélhetőleg gányolás nélkül meg tudod oldani, hogy saját típusú statementet példányosíts, amikor arra van szükséged... Az adapter pattern-t egyébként akkor szokták használni, ha ugyanarra a funkcióra több elég eltérő csomagból származó osztály alkalmas (mondjuk eltérő platformokon), jelen esetben meg arra jó, hogy teszel egy olyan réteget a PDO fölé, amit már át is tudsz írni.
24

Jééé... eltűnt, amit erre válaszoltam...

H.Z. v2 · 2011. Jún. 14. (K), 16.37
Na mindegy, nem írom le újra (de lásd: PDO::setAttribute(PDO::ATTR_STATEMENT_CLASS).

Azzal amit írsz, egy gond van: a PDO néhány metódusa, pl. a prepare v. a query egy-egy PDOStatement osztályú objektumot ad vissza. Ahhoz, hogy ezt úgy cseréljem le, ahogy te javasoltad, felül kellene írnom a PDO megfelelő metódusait egyesével, hogy azok a megfelelő objektum típust adják vissza.
Szóval vagy nem fogtam fel amit írtál vagy ez a módszer célravezetőbb jelen esetben.
25

Jó, csak a te kedvedért

inf · 2011. Jún. 14. (K), 16.49
Jó, csak a te kedvedért ránézek, hogy pontosan hogyan működik a PDO. Tippre arról van szó, hogy a PDO.prepare(blah) példányosít egy PDOStatement-et, aztán annak a metódusaival beállítja rajta a paramétereket. Neked meg ezt a részt kéne újraírnod a saját osztályodban. Ebben az esetben teljesen használható, amit írtam...

szerk:
A PDOStatement leírásában nincs bent a __construct. Az SQL, a PDO objektum, meg a többi paraméter átadása meg valszeg constructor injectionnel megy, szóval ha lehetséges a PDO-tól függetlenül példányosítani a PDOStatement-et, akkor meg lehet csinálni, amit írtam. Ezt leírás hiányában úgy lehet tesztelni, hogy megpróbálod példányosítani, aztán ha valamelyik paramétert hiányolja, akkor sikítani fog miatta, ha meg egyáltalán nem lehet így példányosítani, akkor meg arról szóló hibaüzenetet kapsz, vagy fatal errort, vagy hasonló szépséget.
26

A prepare egy a sok közül,

H.Z. v2 · 2011. Jún. 14. (K), 16.54
A prepare egy a sok közül, aki ilyesmit elkövet.
Persze mindez már csak merőben elméleti dolog, mivel ami miatt felül akartam írni a PDOStatement egyes részeit, az megoldódott azzal, hogy a PDO tud exceptiont visszadobni, ha hibába botlik. :)
27

Ahm. Az alap hibát ott

inf · 2011. Jún. 14. (K), 16.59
Ahm. Az alap hibát ott követted el, hogy belenyúltál a PDOStatement-be. Nem szabad natív osztályokból örököltetni php-nál, mert csak kínlódás lesz a vége... Egyébkéntis felesleges új felelősségi kört adni a PDO-nak vagy bármelyik másik ezzel kapcsolatos osztálynak, helyette inkább új osztályokat kell írni, és azokkal elvégeztetni a dolgokat.
28

Nem, az alapvető hibát ott

H.Z. v2 · 2011. Jún. 14. (K), 17.08
Nem, az alapvető hibát ott követtem el, hogy nem magoltam be a teljes PHP manualt, így azt sem tudtam, hogy az Exception-ök hiánya csak beállítás kérdése. :-)
(sikeresen eldugták, a setAttribute metódus leírását leszámítva, nyomát sem találtam ennek a lehetőségnek )
29

A hibakezelés az a dolog,

inf · 2011. Jún. 14. (K), 17.26
A hibakezelés az a dolog, amit legjobban utálok a php-ben...
30

Vajon miért? :DDD

H.Z. v2 · 2011. Jún. 14. (K), 17.29
Vajon miért? :DDD