Na navigaci | Klávesové zkratky

To Throw or not to Throw Exception? (2.)

David Majda mi poslal v komentářích výborný odkaz na svůj článek, kde upoutává na přestřelku dvou (zřejmě významných) programátorů na téma „výjimky vs. návratové kódy“.

U toho se musím zastavit. A už teď je mi jasné, že se tento seriál trošku protáhne.

Joel vs. Ned vs. dgx

Joel Spolsky tvrdí, že návratové kódy jsou dobré, protože výjimky jsou z nejrůznějších důvodů špatné. Ned Batchelder oponuje, že výjimky jsou kůl, protože návratové kódy jsou fuj.

Pokud trošku „děláte do demagogie“, tak vám z uvedeného je jasné, že taková diskuze je pouhý flame, neb se implikuje nesmyslně. Totiž názor, že něco je špatné, není možné použít jako argument, že něco jiného (a nikoliv doplňkového) je dobré. Či alespoň lepší. To by se mohli hádat donekonečna. Svou pravdu mají oba a jen těžko mohou vyvrátit pravdu toho druhého.

Jak návratové kódy, tak výjimky, mají obrovské nedostatky. Ano, řekl bych, že špatné je obojí. A nemá smysl řešit, co víc. Naopak má smysl nad celou situací trošku popřemýšlet, pokusit se celý problém abstrahovat a najít uspokojivé řešení. A pak se ho pokusit zrealizovat v programovacím jazyce.

No, takže teď už alespoň víte, že tohle není jen další článek na téma Abc je lepší než Xyz 😉

Abstrakce problému

Minule jsem tu naznačoval určitý mechanismus správy chyb, ve kterém hrály hlavní roli tři pojmy: funkce, chyby a varování. Když tak se na to ještě mrkněte.

  • Funkce – základní jednotka programu
  • Chyba – stav, kdy funkce nedosáhne svého cíle. Informace o chybě se předá volající funkci (je ve tvaru, aby ji funkce dovedla pochopit)
  • Varování – informace určená programátorům. Nezpůsobí ukončení funkce, program na ni nereaguje.

Logickou jednotkou programu je tedy funkce. Ta se buď zdárně vykoná a vrátí výslednou hodnotu, nebo dojde k chybě a s tím se funkce ukončí. Volající funkce je o chybě informována a nějakým způsobem ji ošetří. Třeba také vyvolá chybu, nebo varování, či pokračuje po určité větvi vykonávání dále. Nebo ji prostě ignoruje! Ano, ošetření ignorováním je zcela legitimní způsob ošetření.

V reálném světě je tomu stejně. Pokud se drobně škrábneme, nejedeme kvůli tomu do nemocnice, ale problém ignorujeme. V této analogii se výjimky chovají tak, že pokud se dostatečně škrábnutí nebudeme věnovat, dojde k odumření orgánu či dokonce okamžité smrti. Pro návratové kódy by zase sedělo, že sice škrábnutí umí v pohodě přejít, ale ignorují také uříznutí nohy cirkulárkou, neboť obojí jen stěží rozliší.

Volba mezi výjimkami a návratovým kódem je tedy volba mezi rychlou smrtí a postupným vykrvácením, dojde-li k neštěstí. Obojí má své zastánce 🙂

No, a teď zase vážně.

Problematika výjimek

Zatímco minule jsem si stěžoval, jak ubohou informační hodnotu má tzv. chybový návratový kód false, dnes se podívejme, jaké úskalí nám umí přichystat výjimky.

Představme si, že by v PHP najednou všechny funkce začaly namísto chybových kódů (jakým bývá často false) vracet výjimky. Položím vám otázku: co udělá (resp. může udělat) tento kód?

// korektně zjisti jméno uživatele
$user = isset($_GET['user']) && is_string($_GET['user'])
	  ? $_GET['user']
	  : '';

// ořízni na max. délku
$user = substr($user, 0, 30);

// pokusíme se zalogovat
try {
  $logged = in_array($user, myGetAllowedUsers(), true);
} catch (Exception $e) {
  die('Nelze pokračovat.');
}

...

před 18 lety v rubrice PHP | blog píše David Grudl | nahoru

Mohlo by vás zajímat

Komentáře

  1. KLoK #1

    neosetreni navratoveho kodu v pripade ze neni uzivatel v poly $allowedUsers. Dojde k prihlaseni i presto, ze logged je false.

    Ale to je spise logicka chyba nez neosetreni vyjimky

    před 18 lety | reagoval [3] David Grudl [10] Ivan
  2. error414 #2

    avatar

    Nevim co muze kod udelat. Ale je blbost aby funkce kdyz uz by vyhazovala vyjimku in_array tak aby ji vyhazovala kdyz by nenalezla prvek v poli.

    To uz se zabredavame do rizeni toku programu pomoci vyjimek.

    Hlavne by me zajimalo co bude v promene $logged? Kdyz funkce vyhodi vyjimku tak co nacpe do vystupu?

    před 18 lety
  3. David Grudl #3

    avatar

    #1 KLoKu, lehce jsem to upravil, aby kód dával smysl. Přesto háček je jinde a je to tak trošku chyták…

    no chyták – prostě je to zcela regulérní problém výjimek.

    před 18 lety | reagoval [10] Ivan
  4. Ivan #4

    Osobně bych považoval vyhození výjimky ve funkci in_array za poněkud nevhodné. Myslím, že výjimka se vyhazuje ke zpracování nahoru proto, že si s uvedenou situací neumí funkce sama poradit. V tomto případě tedy pokud by in_array neuměla rozhodnout zda v uvedeném poli proměnná je nebo není.

    Naproti tomu, pokud mám metodu, která mi má vrátit pole objektů, které konstruuje podle databáze, byla by od té metody svévole, vyřešit pád databáze vrácením prázdného pole – tady je použití výjimky dle mého názoru oprávněné.

    Nebo jsem něco totálně nepochopil?

    před 18 lety | reagoval [14] Ivan
  5. Ivan #5

    Jo totálně jsem nepochopi :) Předchozí příspěvek je mimo.

    před 18 lety | reagoval [10] Ivan
  6. Ivan #6

    Ale příběh toho kódu je prapodivný… Já ošetřuji blokem try funkci myGetAllowedUsers() a zároveň návratovou hodnotu in_array?

    před 18 lety
  7. Ivan #7

    Neboli – Access denied, vole právě tehdy když nemohu zjistit jací jsou povolení uživatelé ⇒ mě nezajímá, jestli jsi povolenej, pokud já znám své povolené, tak buď vítán :)

    před 18 lety | reagoval [8] David Grudl
  8. David Grudl #8

    avatar

    #7 Ivane, ok, změníme hlášku z ‚Access Denied‘ na ‚Nelze pokračovat‘.

    Zároveň také můžete psát návrhy, jak kód z hlediska návrhu vylepšit.

    před 18 lety
  9. error414 #9

    avatar

    výjimky končí až s jejich ošetřením. dam ruku do ohne ze to ma co delat stimhle

    před 18 lety | reagoval [19] Jakub Podhorský
  10. Ivan #10

    #1 KLoKu, #3 David Grudl $allowedUsers :) tak ono se mi to takhle změnilo pod rukama. Odvolávám co jsem #5 Ivan odvolal :) A už si raději počkám na pointu.

    před 18 lety
  11. Charlie #11

    avatar

    Funkce in_array má návratovou hodnotu boolean, když uživatele nenajde, jednoduše vrátí false a blok try proběhne korektně. Nikdy tak nedojde k zachycení výjimky, protože jí funkce nevyhodí.

    Jediná šance, jak zachytit výjimku, je vyhodit ji ve funkci, která vrací pole uživatelů – to by pak ale byla chyba zdroje dat, nikoliv autentizace uživatele.

    před 18 lety | reagoval [12] error414
  12. error414 #12

    avatar

    #11 Charlie, Představme si, že by v PHP najednou všechny funkce začaly namísto
    chybových kódů (jakým bývá často false) vracet výjimky.

    vice cist

    před 18 lety | reagoval [13] David Grudl [15] Charlie
  13. David Grudl #13

    avatar

    #12 error414, Ale zrovna v případě in_array(), které vrací typ boolean, není false chybovým kódem. Nicméně jsi blízko.

    před 18 lety
  14. Ivan #14

    Za předpokladu, že se má výjimka šířit z myGetAllowedUsers(), tak chybí před try $logged=false; a na konci if($logged)....
    Inu catch nemusí být vždy koš na vše.

    Pokud bylo myšleno, že se výjimka šíří z in_array tak si stojím za #4 Ivan

    před 18 lety
  15. Charlie #15

    avatar

    #12 error414, Pardon, nějak jsem to přehlédl.

    Pak se ale naskýtá otázka, co se stane, když bude vyhozena vyjímka dříve, než dojde ke zpracování té předešlé. Když by všechny funkce vyhazovali Exception místo navrácení false, jednoduše by se tak mohlo stát, že by se skript přehltil vyjímkami.

    před 18 lety | reagoval [16] David Grudl
  16. David Grudl #16

    avatar

    #15 Charlie, Výjimka automaticky přeskočí k „nejbližšímu“ místu zpracování. To je právě pro výjimky charakteristické. Pokud žádné takové místo není, dojde k fatální chybě skriptu.

    před 18 lety
  17. KLoK #17

    Ale porad tam zustava ten logicky problem. Je jedno jestli pole uzivatelu je v promenne nebo funkci.

    Jde o to ze kdyz uzivatel v poli nebude, tak in_array vrati false. A logika algoritmu veli osetrit navratovou hodnotu zpusobem „in_array() or die“.

    Pokud ti jde o to die() v catch bloku, tak tam by mohl byt zakopan pudl. Ja jsem odkojen C++ a tam kdyz zavolas exit() ve vyjimce tak je to proste exit(). Podle toho na co narazis bych tipoval ze PHP to neudela.

    před 18 lety
  18. Ebo #18

    nejlepší je, když se to kousne.. howg 😛

    před 18 lety
  19. Jakub Podhorský #19

    avatar

    halvní problém tohodle kódu vydím to že zachycuješ nejnižší možnou vyjímu čili Exception…ve vyjímkách vidím tu obrovskou výhodu v jejich dědičnosti že si můžeš udělat jejich obrovskou hiearchii a tudíž by zde nemusel být jenom jeden catch…třeba by zde byla vyjímka na neexistující prvek v tom poli a nebo nějaká na odchycení chybového stavu v myGetAllowedUsers() atd. osobně na tom nevidím nic špatného jen to že zde se mi zdá spíš vhodnější kontrola true a false pro funkci in_array() a pro myGetAllowedUsers() nejspíš blok try…chatch

    #9 error414, to je logické po bloku try musí ihned následovat blok catch takhle je to ve všech jazycích které podporují vyjímky

    před 18 lety | reagoval [20] error414 [22] Lando Mata
  20. error414 #20

    avatar

    #19 Jakube Podhorský, to nerikej me ale Davidovi, to mela byt citace z predchoziho clanku.

    před 18 lety
  21. dond #21

    [smazáno] Technická poznámka: Joel se jmenuje Spolsky, ne Sponsky. Ale to jen na okraj.

    Nebudu komentovat PHP, ten „jazyk“ mi k srdci nepřirostl nikdy a v posledních letech mám to štěstí, že v něm nemusím nic dělat, ale co se týče řízení běhu programu, je to známý problém mnoha jazyků (výjimky vs. návratové hodnoty vs. globální proměnné vs. další obskurnosti).

    IMHO obecné řešení neexistuje. Podívejte se, jak se větvení kódu řeší ve funkcionálních jazycích a třeba v zásobníkových jazycích (vlastně nevím, esli se to tak jmenuje, mám na mysli třeba Forth). Obvykle je totiž potřeba se rozhodnout podle konkrétní situace, který způsob je lepší. Jenže to by si člověk musel všechno psát sám a to není in…

    před 18 lety
  22. Lando Mata #22

    #19 Jakube Podhorský, „to je logické po bloku try musí ihned následovat blok catch takhle je to ve všech jazycích které podporují vyjímky

    No, ono to není úplně pravda. Např. v C# můžeš používat i try...finally bez catch. C++ má i další modifikace. Ale to jen na okraj .. 😉

    před 18 lety
  23. David Grudl #23

    avatar

    Tak tedy:

    $user = '';
    $user = substr($user, 0, 30);
    
    // $user nyní obsahuje chybový kód false

    Kdo by to od substr() čekal, že? Je to však zdokumentované chování a musí se s ním počítat.
    Nářků, proč tvůrci PHP s příchodem PHP5 nenahradili všechny chybové kódy za výjimky, jsem slyšel docela dost. V tomto příkladě by vyhodilo výjimku mimo blok try … catch.

    Mohli bychom samozřejmě blok rozšířit:

    try {
      // ořízni na max. délku
      $user = substr($user, 0, 30);
    
      // pokusíme se zalogovat
      $logged = in_array($user, myGetAllowedUsers(), true);
    
    } catch (...) {
      ...
    }

    Jenže co si tím pomůžeme? V bloku catch budeme muset jednak identifikovat zdroj chyby a ačkoliv ji vyhodnotíme jako banální, těžko budeme v započatém logování pokračovat.

    Tak co zkusit třeba:

    try {
      $user = substr($user, 0, 30);
    } catch (...) {
      ...
    }
    
    try {
      // pokusíme se zalogovat
      $logged = in_array($user, myGetAllowedUsers(), true);
    } catch (...) {
      ...
    }

    Ovšem tady už nám výjimky začínají být na obtíž…

    před 18 lety | reagoval [25] martin [29] Ivan [31] Lokutus
  24. Veena #24

    No ale co s tím jinak? Ono:

    if (($user = substr($user, 0, 30)) === false) {
    ...
    } elseif (($logged = in_array($user, myGetAllowedUsers(), true)) === false)
    ...
    }

    neni taky nic parádního.
    Hlavně je to opruz, pokud má člověk snahu o jiné ošetření chyb nebo větvení programu než die(). To by podle mě mohly (sám jsem ješte nedostal odvahu je v php používat) právě vyjímky zajišťovat, tuším.

    Kvituju tvoji snahu se chybovýma stavama probrat a zjistit jak na ně nejlépe.

    před 18 lety
  25. martin #25

    #23 Davide Grudle, zacnem komentar od poslednej casti – preco si myslis, ze v tomto pripade su na obtiz. su predsa uplne rovnako na obtiz, ako kontrolovanie navratovej hodnoty, nie (alebo vadi ten jeden riadok naviac) ?
    vyhoda vyjimiek (neviem, ako je to presne v php, ale runtime-ovych v jave) je ta, ze sa daju odchytavat na ktorejkolvek urovni zanorenia programu. t.j. su chyby, s ktorymi si volajuci kod vie poradit a tie by mal osetrit. tie, ktore osetrit nechce necha prebublat vyssie. a na niektorej urovni sa pravdepodobne odchytia vsetky dovtedy nezpracovane chyby – coz ma vo web aplikaciach potom za nasledok zobrazenie stranky s chybovou hlaskou typu „nastala chyba pri spracovavani poziadavku, skuste poziadavok neskor“. a naviac vyjimka so sebou nesie stack trace, takze pri zalogovani chyby na ktorejkolvek urovni je relativne lahko dohladatelny zdroj chyby. takze osobne si myslim, ze kod vobec nemusi osetrovat vsetky chyby, ktore mozu vzniknut vo funkciach, ktore vola, ale aplikacia by mala byt pisana tak, aby si vedela na niektorej urovni z vynimkou poradit.

    před 18 lety | reagoval [45] David Grudl
  26. Pavel #26

    Já bych to napsal takto:

    try {
      logged = inArray(getUser(), myGetAllowedUsers());
    } catch (anException e) {
      die("Nelze pokračovat.");
    } catch (anotherException e) {
      die("Taky nelze pokračovat.");
    }

    Ale myslím si, že Davidovi jde o tu výjimku vyhazovanou funkcí substring(), která by se musela na každém místě ošetřovat (ať tak či onak). Výjimky se „dle doporučení“ mají používat s rozvahou a metoda na vybrání podřetězce by podle mě „checkovanou“ výjimku rozhodně produkovat neměla…

    před 18 lety
  27. marco #27

    avatar

    trochu offtopic: $_GET[‚user‘] je vzdy string ak je definovana, cize druha polovica podmienky je zbytocna

    před 18 lety | reagoval [40] raver
  28. pok #28

    avatar

    No, pokud by všechny funkce vyhazovaly jen vyjímky, tak by stačilo tohle ne?

    try {
      // zjistime jmeno uzivatele
      $user = $_GET['user'];
    
      // ořízni na max. délku
      $user = substr($user, 0, 30);
    
      // zalogujeme se
      $logged = in_array($user, myGetAllowedUsers(), true);
    } catch (Exception $e) {
      die('V prubehu logovani neco selhalo');
    }

    Zalogování je přeci operace ve stylu „povede se všechno a já se přihlásím“, nebo „smůla“. Myslím, že nevýhoda vyjímek na kterou se snažíš upozornit je že jejich nahození ukončí daný blok programu.

    před 18 lety | reagoval [44] David Grudl
  29. Ivan #29

    #23 Davide Grudle, Hm, kdo by to čekal… Že subStr('a', 0, 30) == 'a', ale subStr('', 0, 30) === false :(
    V jiných jazycích to funguje dle mého názoru logičtěji:
    ''[:30] vrací '' (python), ''[0...30] také vrací '' (ruby)
    Takže dle mého spíše ne všechno automaticky na výjimky, ale domyslet vhodnost.

    před 18 lety
  30. David Majda #30

    avatar

    S případnou vyjímkou v substr() počítat v kódu NEMUSÍME z toho důvodu, že se jí lze na 100% vyhnout správným použitím té funkce. V tomto případě je jasně definováno, kdy ze substr() ta vyjímka vypadne a lze to při volání zařídit tak, aby tato situace nenastala. Je to úplně totéž, jako kdybys chtěl ošetřovat catch-blokem každé dělení, protože to má taky nedefinované případy (dělení nulou).

    V Javě analogie této funkce (String.subString) ) vyhazuje IndexOutOfBoundsException, což je unchecked vyjímka, tedy její ošetření není povinné. V PHP jsou unchecked všechny vyjímky, takže tady není co řešit. V Javě je právě třeba často hlídat, zda se uživatel funkce může vyjímce vyhnout, a podle toho vyhazovat buď unchecked nebo checked exception. Ale to už trochu odbočuju.

    Suma sumárum, myslím, že jsi zvolil špatný příklad.

    před 18 lety | reagoval [37] martin
  31. Lokutus #31

    #23 Davide Grudle,

    $user = '';
    $user = substr($user, 0, 30);
    
    // $user nyní obsahuje chybový kód false `

    No jistě, co bych taky měl očekávat jiného v proměnné typu strring.
    Uff, díky bohu, že jde PHP úplně mimo mě.

    před 18 lety | reagoval [32] Lokutus
  32. Lokutus #32

    #31 Lokutusi, Hele, já myslel, že když zmáčknu tady to čudlítko s nápisem CODE, tak se ta ohraničená část textu zformátuje. A ono prd. Nebo jsem to zmáčknul blbě?

    před 18 lety
  33. Mordae #33

    avatar

    To, že substr() vůbec vrací false je chyba PHP, ne výjimek. Správné chování je IMO vrátit text nalezený do 30 znaků, nebo konce textu (co přijde dříve), stejně, jako při čtení ze streamu.

    Kód by měl při správné implementaci vypadat asi takto:

    try {
    	$user = Script::getStringArgument('user');
    } catch ( Script_BadArgumentTypeException $e ) {
    	die('Argument "user" musi byt retezec.');
    }
    
    $user = substr($user, 0, 30);
    
    try {
    	$logged = in_array($user, Auth::getAllowedUsers(), true);
    } catch (Auth_UserListRetrievalException $e) {
    	die('Nepodarilo se ziskat seznam opravnenych uzivatelu.');
    }
    // ...
    před 18 lety | reagoval [34] martin
  34. martin #34

    #33 Mordae, a ako ste prisiel na to, ze substr nemoze failnut? napada ma celkom dost dovodov, ktore moze zapricinit vyhodenie vyjimky v metode substr

    před 18 lety | reagoval [35] Ivan
  35. Ivan #35

    #34 martine, Můžete důvody konkretizovat?

    před 18 lety | reagoval [36] martin
  36. martin #36

    #35 Ivane, napr. null ako prvy parameter, nieco ine ako retazec ako 1. prarmeter, nieco ine ako cislo ako dalsie 2 argumenty. 2. argument vacsi ako dlzka retazca. 2. alebo 3. argument negativny…

    před 18 lety | reagoval [38] Ivan [42] Adam Hošek
  37. martin #37

    #30 Davide Majdo, hmmm, IndexOutOfBounds ale musis (mal by si) tiez niekde osetrovat. pravdepodobne (skoro urcite) nie hned pri volani danej fcie, ale na urcitej urovni by osetrena mala byt – teda pokial nechces, aby ti to sundalo celu jvm – coz ja vacsinou nechcem :)

    před 18 lety | reagoval [39] martin
  38. Ivan #38

    #36 martine, $user = substr($user, 0, 30); – 2. a 3. parametr jsou tady mimo hru. $user = Script::getStringArgument('user'); – tady bych řekl, že to bude vracet string. Ale obecně máte pravdu – a je to slabina (?) slabě typových jazyků. (tedy, co se stane když bude např. 2 parametr ‚abc‘? Nefailne to, ale bude tam 0 – inu php :) Pokud byste v kódu připustil možnost zmatení parametrů, byla by výjimka na místě (podle mě mnohem lepší než vyhodit notice a zkusit pokračovat – jak to je teď).

    před 18 lety | reagoval [39] martin [42] Adam Hošek
  39. martin #39

    #38 Ivane, ale vy sa pozerate na konkretne pouzitie. 2. a 3. argument nemusia byt staticke, ako v tomto priklade. mozu byt vypocitane, a vypocitane nespravne. preto by ich funkcia substr mala kontrolovat a vracat chybu (ci uz vynimku alebo false) v pripade nespravneho pouzitia. rovnake veci platia aj pre prvy parameter. ale ako som pisal aj v prispevku #37 martin, netreba tieto chyby riesit hned v kode, ktory metodu vola – staci na istej urovni osetrit vacsinu takychto typov chyb (v jave runtime-ovych) naraz.

    před 18 lety | reagoval [41] Ivan [42] Adam Hošek
  40. raver #40

    avatar

    #27 marco, a co taketo url:

    index.php?user[a]=nieco

    před 18 lety
  41. Ivan #41

    #39 martine, Máte pravdu. Asi se nebudeme dál přít konkrétní x obecně…

    před 18 lety
  42. Adam Hošek #42

    avatar

    #36 martine, To je demagogie. Pokud jde o PHP, pak by se někde uvnitř té fce mohlo převést přetypování (které snad žádné chyby nehází) a tudíž by prvním argumentem byl vždy string a další by byly vždy čísla (i kdyby 0). Jediný stav, kdy by ta fce mohla něco házet, je hodnota null. Nevim, jak se v tomhle případě PHP chová… snad převede hodnotu na "(null)" nebo co já vim.

    V silně typových jazycích jiné typy, než definované hlavičkou funkce, použít nejde už v době kompilace a null je často odchytáván běhovou výjimkou NullPointerException nebo něčím podobným.

    #38 Ivane, Přetypování (int)"abc" na 0 je samozřejmě to, na čem PHP stojí a padá… bohužel nebo bohudík 🙂.

    #39 martine, Zase narážíme na to, jak je PHP stavěné a jak se chová a co z toho pro programátory plyne. Buď ta fce vrací to své univerzální false nebo může házet (pokud se má vše vyhazovat) IllegalArgumentException. No a je to zase zde – takhle by se mohla chovat každá funce v PHP. Pak si ale představme, jaký by byl svět peklo… na každém kroku ošetřování legálnosti argumentů… Kontrovat Javou asi neni úplně to nejlepší, co tady můžeme dělat…

    …mám totiž pocit, že David se snaží rozebrat problematiku výjimek v PHP a ne jinde. I když srovnání má svou váhu.

    Podle mě situace, aby ve slabě typovém jazyce (PHP) byly hojně užívány výjimky, je cesta do pekel. Navíc implementace té které funkce může být různá a dá se říct, že si v jednom jazyce můžu napsat pět různých implementací např. fce `substring() ` tak, abych pokryl všechny možné způsoby návratu chyby včetně všech možných typů chyb… no možná by těch implementací bylo víc 😉. Pak si můžu vybrat, jaké chyby chci dostat a použít konkrétní implementaci… srandičky 😉.

    Vyčítat výjimkám jejich náročnou implementaci (bylo myšleno jako implementace ze strany jazyka/překladače/běhového prostředí nebo ze strany jejich používání? – komentuji první variantu) a snižování výkonu podle mě nemá smysl. Je to jedna z vlastností daného jazyka, která je implementovaná jednou a kvalitně (co do omezení chyb v implementaci) a která má svůj účel – ulehčit práci při běžném programování tak, aby programátor psal s pomocí těch konstrukcí programy s menším výskytem logických chyb, resp. aby bylo možné tyto chyby snadno lokalizovat a jednoduše ošetřit (pokud je to možné). Pokud mi jde o výkon, můžu programovat v C/C++ a kašlat na OOP, výjimky a všechna ta cukrátka, díky nimž lze dnes programovat pohodlněji.

    Uff a howg! 🙂

    před 18 lety | reagoval [44] David Grudl
  43. Adam Hošek #43

    avatar

    A jsem tedyk zvědav na pokračování 🙂.

    před 18 lety
  44. David Grudl #44

    avatar

    #28 poku, v podstatě jsi na to kápl. Vyhození vyjímky mě teleportuje pryč do míst, odkud se jen těžko budu vracet do započaté práce.

    Ošetřit a rozhodnout se, zda (či kudy) pokračovat – tak to mám rád.

    Bohužel u výjimek mě jímá paranoa, protože nevím, co všechno ji může vyhodit. Nevím, kde všude je skryté „goto“.

    Ono se nedá říci, že logování je operace, kdy buť všechno proběhne nebo nic. Jako programátor chci sám určovat váhu jednotlivým operacím. A drobná chyba substr() vs. nemožnost zjistit pole uživatelů je podstatný rozdíl.

    (tím nechci říct, že lze přehlížet problém se substr (tedy v PHP možná i lze, ale není to čisté))

    #42 Adame Hošku, připouštím, že tyhle úvahy jsou velmi silně spjaty právě s PHP.

    před 18 lety | reagoval [47] martin
  45. David Grudl #45

    avatar

    #25 martine, zcela s tebou souhlasím. Co může být horšího, než klasická PHP chybová hláška, neobsahující stacktrace a kterou lze buď utlmunit, nebo logout a pak pracně zkoumat původ.

    Přesto vidím na výjimkách i negativa.

    před 18 lety | reagoval [46] Adam Hošek
  46. Adam Hošek #46

    avatar

    #45 Davide Grudle, A jak se jednou člověk sžije s něčím jako je např. (tolikrát přirovnávaná) Java, PHP pak dokáže být noční můrou. Občas ta hlášení chyb jsou tak nejasná, že člověk stejně matně tápe, kde je skutečný původ té chyby. (Mám na mysli víceméně běhové chyby.) A co je nejhorší: když je chyba v eval()'d kódu… no ale to už asi nakusuju téma eval() || !eval()? 😉.

    před 18 lety
  47. martin #47

    #44 Davide Grudle, „Ošetřit a rozhodnout se, zda (či kudy) pokračovat“ – mozno to je presne ono – mne sa prave nechce po pri volani kazdej metody riesit chybovy stav – chcem si vyberat miesta, kde tie chyby riesit budem – a casto na jednom mieste riesit chyby z vacsej sady volanych funkcii.

    před 18 lety | reagoval [48] Adam Hošek
  48. Adam Hošek #48

    avatar

    #47 martine, To je fajn, to nepopírám, dokonce souhlasim. Ale co když mezi jednotlivými úkony, z nichž touto metodou sbírám „odezvy“, je nějaký silnější vztah? Závislost, která mě nutí řešit problém před provedením dalšího úkonu? Je pravda, že série příkazů, kdy každý krok je zvlášť šetřen (jakoukoli z metod – výjimky, chybové kódy), aby bylo možné rozhodovat, jestli nadále můžu provést krok následující i při výskytu ošetřitelné chyby, je otravná na psaní i čtení.

    Pokud je jakékoli selhání kritické pro další operace, je uvedení celého bloku úkonů do try-catch bloku celkem vhodné, přehledné atd. Otázkou je, jestli a za jakých chybových stavů je potřeba pokračovat v původním plánu? Proto se také doporučuje používat výjimky jen pro skutečně vyjímečné stavy. A to i v ohledu na výkon výjimek.

    Např. u fce substr() je házení někde výše zmíněné výjimky typu IndexOutOfBoundsException (nebo nevím, jak tomu v tomhle případě říkat) docela trefné. Přecejen ten interval, který chceme vycucnout, většinou vypočítáme předem a obvykle v závislosti na délce cucaného řetězu. (Omlouvám se za slovník 😁.) Tj. pokud by zde došlo k chybě, asi bude oprávněně výjimečná a určitě běhová.

    před 18 lety | reagoval [51] martin
  49. piler #49

    Zdravim, trosku mimo temu, ale viete mi poradit, ci dat alebo nedat objekt do session?

    Viete o nejakych nebezpecenstvach alebo o niecom inom, kvoli comu by sa objekt v session nemal prenasat?

    dik ;)

    před 18 lety | reagoval [51] martin
  50. marco #50

    avatar

    ok, beriem spat ;)

    před 18 lety
  51. martin #51

    #48 Adame Hošku, mno ja na vyjimkach vidim prave tu vyhodu, ze pokial chcem, tak problem mozem osetrit hned na mieste (po volani funkcie), alebo jeho osetrenie mozem nechat na nejake spolocne osetrenie. to je prave ta vyhoda, ze sice sa musim rozhodovat, ci vyjimku chybu vo funkcii osetrovat alebo nie, ale nemusim ju osetrovat hned, na rozdiel od navratovych kodov.
    #49 piler jediny problem, co ma napada, je velkost objektu a jeho pripadna serializacia a replikovanie pri pouziti clusteru.

    před 18 lety | reagoval [52] Adam Hošek
  52. Adam Hošek #52

    avatar

    #51 martine, Samozřejmě… možnost nechat „odvést“ výjimky na nějakou vyšší úroveň jsem při psaní toho komentáře asi opomněl. To jednoznačně výhodou je. Zvláště když to umí programátor dobře používat.

    před 18 lety
  53. llook #53

    avatar

    Ok, let's flame.

    Připomněl bych tři způsoby zpracování výjimečných stavů, zmíněné v předchozím článku:

    • návratové hodnoty
    • globální proměnná či funkce
    • výjimky

    Osobně preferuju všechny tři, v různých situacích přijdou vhod různá řešení.

    Výjimky jsou bezva ve dvou případech:

    1. Provádím sekvenci operací a potřebuju provést všechno nebo nic. Typickým příkladem jsou DB transakce, lze najít i jiné příklady.
    2. Nastala kritická chyba, ale je určitá šance, že někdo tam venku s tím počítá a umí ji ošetřit. Možná to neumí volající, možná až volající volajícího nebo ještě dál a teprve pokud s tím opravdu nikdo nepočítá, tak ať program kiksne.

    Globální proměnné či funkce jsou nejmocnější ve spojení s návratovými hodnotami. Příklad:

    if (!něcoUdělej()) {
        // teď mě nezajímá, proč to nevyšlo
        // stačí mi vědět, že to "prostě nevyšlo"
        echo 'No, nevyšlo to...';
    }
    
    if (!něcoUdělej()) {
        // tentokrát mě to ale zajímá a false mi nestačí
        echo 'Nevyšlo to, protože: ' . posledníChybovka();
    }

    V praxi by něcoUdělej mohlo být PDO::query a posledníChybovka potom PDO::errorCode, třeba.

    Moje stanovisko: „v některých situacích to throw exceptions!“

    před 18 lety
  54. kolemjdoucí #54

    Mně se zdá, že objevujete Ameriku. Někdy je třeba ošetřit chybu hned – pak jsou výjimky opruz. Někdy je lepší ošetřit chybu později a jinde – pak jsou opruz návratové kódy. Takže částečným řešením je pořádně přemýšlet při návrhu, ale stejně se nezavděčíte všem ve všech situacích.

    před 18 lety
  55. Miloslav Ponkrác #55

    Používám výjimky řadu let v různých jazycích. Dgx se dostává do problémů proto, že se snaží věci dělat ad absurdum.

    Některé věci je lépe ošetřit hned, jiné vyhozením výjimky, další třeba návratovou hodnotou, něco prostě není vůbec chyba, jen speciální stav, jindy je lépe svést chyby pomocí goto do jednoho místa. Některým chybám lze předejít testováním stavů a podmínek. Taky se může hodit nastavit globální proměnnou, nebo zalogovat, atd..

    Všechno chce cit pro situaci a používat výjimky všude a za každou cenu je prostě blbost. Důsledkem je, že pokud používáte knihovnu od někoho, kdo neumí s výjimkami zacházet a přesto je používá, je to příšerná věc a pak je lepší, když se takovému člověku výjimky zakážou úplně. Nadělá pak méně škody.

    Tedy závěr: Výjimky jsou JEDNÍM Z MNOHA prostředků, jak se vypořádat s neovyklými stavy (záměrně nepíšu s chybami, protože výjimky nejsou na chyby). Výjimky jsou skvělá věc, já programovací jazyk bez výjimek považuji za nedokonalý, ale ošetřovat vše jen pomocí výjimek je blbost. Navíc je potřeba říci, že výjimky jsou sice velmi luxusní prostředek, ale také velmi pomalý, pokud nastane vyjímečná událost. Pokud v programu lítá milióny vyhozených výjimek za sekundu, pak takový program bude zpravidla velmi pomalý. Tedy všeho s mírou.

    před 18 lety | reagoval [56] martin
  56. martin #56

    #55 Miloslave Ponkráci, milion neobvyklych stavov za sekundu, to chce programatora frajera :))

    před 18 lety
  57. Kamzik II #57

    No ja newim, podstatou vyjimek by melo bejt reagovani na stav, kterej by se mel nejak osetrit 😉
    takze pokud se jedna o prihlasovani, tak mi urcite neni
    jedno, ze se nekdo pokousi prihlasit pod ne-existujicim uzivatelskym jmenem – proste vyhodim vyjimku, a „pak“ se s tim proste nejak (treba vypisu chybovou hlasku) poperu. Pokud by byl celej system byl psan objektove, tak by tady ten problem, alespon si myslim, nebyl. Svet by byl jednodussi a vyjimky by nam ulehcovali a zprehlednovali zivot. Doufam, ze sem se vyjadril spravne…

    Kamzik II 😉

    před 18 lety
  58. Miloslav Ponkrác #58

    To není až tak nemyslitelné, záleží co kdo považuje za hodné výjimky. Ale to se stává jen těm, kteří výjimky dotahují absolutně do absurdna.

    před 18 lety
  59. Miloslav Ponkrác #59

    Výjimky a objektové programování spolu až tak moc nesouvisí. Výjimky lze používat velmi úspěšně i bez objektů, třeba jádro Windows vyhazuje výjimky, ač je psané v C, které podporu pro objekty postrádá.

    Objektové programování není jediný existující styl programování a jediné paradigma. Výjimky nepotřebují objekty, nejsou na objektech nikterak závislé. A to i když v mnoha jazycích se vyhazují instance objektů, ale není to podmínkou.

    před 18 lety | reagoval [60] Kamzik II
  60. Kamzik II #60

    #59 Miloslave Ponkráci, No ja bych rekl, ze pouzivani vyjimek bez oop je prasarna, ne?

    před 18 lety | reagoval [61] Kamzik II [62] llook
  61. Kamzik II #61

    #60 Kamziku II, Mozna neni 😉 A co se tyce clanku, tak bych se priklonil k vyhazovani vyjimek 😉

    před 18 lety
  62. llook #62

    avatar

    #60 Kamziku II, Mě to připadá, že si říkáš o přizvukování. Aby ti někdo napsal, že „výjimky bez OOP jsou prasárna, s tím rozhodně souhlasím“. To ti nenapíšu, radši se zeptám:

    Proč myslíš, že výjimky bez OOP jsou prasárna? A proč by ses v článku přiklonil k vyhazování výjimek?

    před 18 lety | reagoval [63] Kamzik II
  63. Kamzik II #63

    #62 llooku, Ono slo spis o to, ze jsem napsal blbost, uvedomil jsem si to, tak sem se opravil 😉 A jinak ja vyhazuju vyjimky kde to jde, protoze to podle meho nazoru prispiva k logice a k prehlednosti kodu. A zatim me jeste nikdo nepresvedcil o opaku, muzes byt prvni :)

    před 18 lety

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.


phpFashion © 2004, 2024 David Grudl | o blogu

Ukázky zdrojových kódů smíte používat s uvedením autora a URL tohoto webu bez dalších omezení.