Co kdyby se E_WARNING převáděly na výjimky?
- David Grudl
- Nette Core | 8227
Pohrávám si v hlavě s trošku revolučním krokem: co kdyby se standardně E_WARNING převáděly na výjimky?
Částečně by to změnilo způsob programování v PHP a uvažování nad kódem (což je zároveň i největší problém). Místo
$handle = fopen('file', 'w');
if (!$handle) ...
fwrite($handle, $s);
by se dalo psát
try {
fwrite(fopen($handle), $s);
} catch (PHPException $e) {
...
}
Zachovala funkce zavináče, který by výjimky potláčel.
Aby to bylo použitelné a přínosné, muselo by být tohle chování výchozí.
Poznámky k dalším úrovním:
- E_RECOVERABLE_ERROR a E_USER_ERROR už se na výjimky převádí dlouho
- E_STRICT, E_DEPRECATED a E_USER_DEPRECATED převádět na výjimky by bylo vyloženě kontraproduktivní
- E_NOTICE jsem na rozpacích, tam by bylo potřeba rozlišovat
- E_USER_NOTICE, E_USER_WARNING nejspíš nepřevádět, programátor by mohl vyvolat výjimku rovnou
- E_ERROR, E_PARSE, E_COMPILE_ERROR, E_CORE_ERROR, E_COMPILE_WARNING, E_CORE_WARNING nás nemusí zajímat, vedou obvykle k fatal error
- Patrik Votoček
- Člen | 2221
Takvéto chování se dá vyvolat už dnes né?
Nette\Debug::$strictMode = TRUE;
?
$i++;
- David Grudl
- Nette Core | 8227
Strict mode je trošku něco jiného: nevyhazuje výjimku ale natvrdo vyvolá červenou blue-screen v případě čehokoliv. Samotné pojmenování strictMode je trošku zavádějící a vhodnější by bylo $immediateDeath.
- Majkl578
- Moderator | 1364
Jsem pro, aby defaultně PHPException vyhazovala jakákoliv chyba (včetně
např. E_NOTICE a E_DEPRECATED) s tím, že by to šlo nějak ovlivnit (něco
jako Nette\Debug::errorLevel(E_ALL ^ E_NOTICE)
).
úrovně E_STRICT a E_DEPRECATED převádět na výjimky by bylo kontraproduktivní
Může mi tohle prosím někdo dovysvětlit? Nechápu proč kontraproduktivní, tyto standardy striktně dodržuji.
PS: Aktuálně používám Debug::$strictMode = TRUE
a
error_reporting(E_ALL | E_STRICT)
.
- hrach
- Člen | 1838
jsem proti ;-) asi jediný. ale dokud php nebude mít finally
,
tak prostě „není“ připravené na výjimky… musí se to pak řešit
všemožnými stavovými proměnnými, kod je ještě nepřehlednější…
takže! :D za mě -1
ale pokud by to obnášelo, že nette přidá
podporu pro finally, tak bych byl určitě pro. :)
- David Grudl
- Nette Core | 8227
Majkl578 napsal(a):
Může mi tohle prosím někdo dovysvětlit? Nechápu proč kontraproduktivní, tyto standardy striktně dodržuji.
Protože nejde o chyby (tj. nijak neovlivní fungování programu), jen upozorní programátora, že došlo například k přejmenování funkce apod. Takové upozornění stačí zalogovat.
- David Grudl
- Nette Core | 8227
hrach napsal(a):
jsem proti ;-) asi jediný. ale dokud php nebude mít
finally
, tak prostě „není“ připravené na výjimky…
S tím nesouhlasím. Finally je nutnost u jazyků bez garbage collectoru, v případě PHP ho potřebuješ velice výjimečně.
- marek.dusek
- Člen | 99
OT ad finally – ukaz jediny priklad, kde je nutne potreba, resp. kde by neco usnadnilo?
- hrach
- Člen | 1838
jasný, v php není třeba řešit ten uklid, jde ale spíš o filozofii struktury a funkce kodu. flash message o uspesnem provedeni pridam az ve finally, nebudu to cpat na konec try… proste
<?php
try {
// whatever
} catch (PHPException $e) {
$this->addFlashMessage('Editace se nepodařila.');
$this->redirect...
} finally {
$this->addFlashMessage('Editace se podařila.');
$this->redirect...
}
?>
nebo mám špatné vnímání výjimek? :) takhle mi to přijde správně
- Ondřej Brejla
- Člen | 746
Řekl bych, že vnímání finally
bude asi trošku špatné :)
Jestli to chápu, tak ho chceš používat jako
if VSECHNO OK then FINALLY else CATCH
…což je samozřejmě
špatně, protože finally
se provádí vždy, ať už proběhne
catch
blok nebo ne.
Editoval Ondřej Brejla (15. 7. 2010 21:17)
- jiriknesl
- Člen | 56
Já se bojím toho, že by vyjímky zabily výkon. Jinak jsem pro. A navíc bych bral, kdyby Nette 1.0 mělo třídy String a Array (klidně vyber mého Googyho).
Hrach: Finally skutečně moc nepotřebuješ…
respektive co je špatného na:
<?php
try {
// whatever
$this->addFlashMessage('Editace se podařila.');
$this->redirect...
} catch (PHPException $e) {
$this->addFlashMessage('Editace se nepodařila.');
$this->redirect...
}
?>
- marek.dusek
- Člen | 99
Tak toto je nonsense – finally se provede VZDY, tj. v pripade chyby se ti vypise „ko“ a pak „ok“ ;)
Finally je pro jazyky, ktere nemaji destruktory – tam je treba delat ruzne stream.close() atp. (tedy cleanup, coz je 99% uziti finally) Php toto ma osetrene paradne, proto zadne finally nepotrebuje.
EDIT: reagoval jsem samozrejme na Hracha
Editoval marek.dusek (15. 7. 2010 21:15)
- David Grudl
- Nette Core | 8227
jiriknesl napsal(a):
Já se bojím toho, že by vyjímky zabily výkon.
To rozhodně ne. Kolik ti udělá aplikace za den warningů? ;)
A navíc bych bral, kdyby Nette 1.0 mělo třídy String a Array (klidně vyber mého Googyho).
Tohle prosaď na php.net a budu ti vděčný!
- odin
- Člen | 50
David Grudl napsal(a):
Pohrávám si v hlavě s trošku revolučním krokem: co kdyby se standardně E_WARNING převáděly na výjimky?
Částečně by to změnilo způsob programování v PHP a uvažování nad kódem (což je zároveň i největší problém). Místo
$handle = fopen('file', 'w'); if (!$handle) ... fwrite($handle, $s);
by se dalo psát
try { fwrite(fopen($handle), $s); } catch (PHPException $e) { ... }
Takze to znamena, ze vsechen normalne napsany kod (ktery kontroluje navratove hodnoty funkci, ktere neco vraci), bude k nicemu, protoze najednou bude hazet vyjimky? Takze se bude muset prepsat?
-1
Krome toho to v uvedenem prikladu nepoznam jestli selhal fwrite nebo fopen. Jo u banalnich CRUD aplikaci, ktere proste kdyz nevi, tak napisou „Internal error“ to asi nevadi. Ale v aplikaci, ktera neco udelat musi, je to dost velky problem.
-1
- David Grudl
- Nette Core | 8227
Takze to znamena, ze vsechen normalne napsany kod (ktery kontroluje navratove hodnoty funkci, ktere neco vraci), bude k nicemu, protoze najednou bude hazet vyjimky? Takze se bude muset prepsat?
Nikoliv, pokud si teda pod pojmem „normalne napsany kod“ představujeme kód, který nevyhazuje warningy.
Krome toho to v uvedenem prikladu nepoznam jestli selhal fwrite nebo fopen. Jo u banalnich CRUD aplikaci, ktere proste kdyz nevi, tak napisou „Internal error“ to asi nevadi. Ale v aplikaci, ktera neco udelat musi, je to dost velky problem.
V uvedeném příkladu se to neřeší. Pokud bych to rozeznat potřeboval, rozdělím kód do dvou sekcí try … catch. Obdobně, jako když dvakrát testuju návratovou hodnotu.
- Ondřej Mirtes
- Člen | 1536
Na jednu stranu je to zajímavý nápad, na druhou stranu je to magie. Magie, která činí kód nepřenositelným. Nechci se ve svých třídách spoléhat na to, že poběží v prostředí Nette. (Konkrétně, že budou někam includovány po zavolání Debug::enable(), který asi toto chování spustí.)
Je to velký zásah do chování jazyka. Jako proof-of-concept pěkné, ale do ostré verze tomu nejspíš podporu nevyjádřím.
- marek.dusek
- Člen | 99
minus 1
Takova blbinka, ktera ma imho nulovou pridanou hodnotu, ale nuti predelat vsechen kod – to uz nic jineho k reseni nezbyva? :-)
Editoval marek.dusek (17. 7. 2010 0:02)
- Honza Kuchař
- Člen | 1662
Zajímavá myšlenka, akorát je problém s tou přenositelností kódu. Já opravdu nevím, jestli podpořit nebo odporovat. Ale jako koncept je to opravdu parádní.
- Blizzy
- Člen | 149
hrach napsal(a):
jasný, v php není třeba řešit ten uklid, jde ale spíš o filozofii struktury a funkce kodu. flash message o uspesnem provedeni pridam az ve finally, nebudu to cpat na konec try… proste
<?php try { // whatever } catch (PHPException $e) { $this->addFlashMessage('Editace se nepodařila.'); $this->redirect... } finally { $this->addFlashMessage('Editace se podařila.'); $this->redirect... } ?>
nebo mám špatné vnímání výjimek? :) takhle mi to přijde správně
marek.dusek napsal(a):
Tak toto je nonsense – finally se provede VZDY, tj. v pripade chyby se ti vypise „ko“ a pak „ok“ ;)
V případě chyby se vypíše „ko“, a pak se přesměruje, jen pro upřesnění. ;-)
- na1k
- Člen | 288
Blizzy, myslím že marek.dusek se bavil obecně o koncepci try-catch-finally a tam skutečně platí, že blok finally se provede vždy – ať už se výjimka vyhodí anebo ne.
To že v Nette způsobí redirect ukončení provádění kódu je sice pravda, ale v téhle věci je to irelevantní, protože php blok finally nemá a ani jej nepotřebuje (kvůli již zmíněnému garbage collectoru).
Naprosto korektní mi to přijde takto
try {
// whatever
$this->addFlashMessage('Editace se podařila.');
$this->redirect...
} catch (PHPException $e) {
$this->addFlashMessage('Editace se nepodařila.');
$this->redirect...
}
Editoval na1k (17. 7. 2010 23:43)
- Blizzy
- Člen | 149
na1k: Mě to tak naprosto korektní taky přijde, používám to, a nemám s tím problém, hrachova řešení finally se nijak nezastávám, já finally nepotřebuju. Nicméně je pravda, že dvě hlášky jeho kód nevypíše.
Abych tady nepsal jenom offtopic, rád bych napsal toto:
Podle mě je to příliš velký zásah do jazyka, moc se mi nelíbí představa, že to bude v Nette defaultně zapnuté a kód pro Nette bude už jiný jazyk. Radši bych, kdyby se to mělo objevit v PHP 6.
Editoval Blizzy (18. 7. 2010 1:04)
- hrach
- Člen | 1838
napsal sem ± blbost, už to tady padlo; nicméně je tu opravdu ten fakt, že pokud použiji cizí knihovnu, která může mít jeden jediný neošetřený warning, už mi spadne aplikace. A teď bych samozřejmě mohl rozjímat nad tím, že daný warning se generuje jen při určitém vstupu, který nejsem schopen zjistit vlastním testováním… nebezpečí hrozí takhle víc, než se zdá…
Editoval hrach (18. 7. 2010 11:13)
- paranoiq
- Člen | 392
Blizzy napsal:
Podle mě je to příliš velký zásah do jazyka, moc se mi nelíbí představa, že to bude v Nette defaultně zapnuté a kód pro Nette bude už jiný jazyk.
to přeci vůbec nevadí. frameworky mají v popisu práce měnit jazyk k lepšímu
Radši bych, kdyby se to mělo objevit v PHP 6.
a zpětná kompatibilata jazyka?! framework si tohle dovolit může, jazyk nikoliv
hrach napsal:
nicméně je tu opravdu ten fakt, že pokud použiji cizí knihovnu, která může mít jeden jediný neošetřený warning, už mi spadne aplikace.
o tom už psal Jirka Knesl. řešení: vypnout výjimky, zavolat cizí knihovnu, zapnout…
- odin
- Člen | 50
David Grudl napsal(a):
Takze to znamena, ze vsechen normalne napsany kod (ktery kontroluje navratove hodnoty funkci, ktere neco vraci), bude k nicemu, protoze najednou bude hazet vyjimky? Takze se bude muset prepsat?
Nikoliv, pokud si teda pod pojmem „normalne napsany kod“ představujeme kód, který nevyhazuje warningy.
Takze to znamena, ze aby nette nehodilo vyjimku, tak pred vsema funkcema, ktere muzou generovat warning musi byt zavinace?
- Peppy
- Člen | 137
paranoiq napsal(a):
frameworky mají v popisu práce měnit jazyk k lepšímu
…
a zpětná kompatibilata jazyka?! framework si tohle dovolit může, jazyk nikoliv
Kompatibilita by sa vyriešila, to nechaj na php.net, ale framework v php nemá právo zasahovať do syntaxe jazyka…
Editoval Peppy (18. 7. 2010 15:18)
- David Grudl
- Nette Core | 8227
odin napsal(a):
Takze to znamena, ze aby nette nehodilo vyjimku, tak pred vsema funkcema, ktere muzou generovat warning musi byt zavinace?
Uzavíráš funkce, které mohou generovat výjimky, do prázdného
try { } catch()
?
- David Grudl
- Nette Core | 8227
Honza Kuchař napsal(a):
Zajímavá myšlenka, akorát je problém s tou přenositelností kódu. Já opravdu nevím, jestli podpořit nebo odporovat. Ale jako koncept je to opravdu parádní.
Asi jediná možnost je to zkusit nějakou dobu používat a pak se rozhodnout. Na měsíc to zkusím a uvidím.
Nicméně – před lety byl i koncept třídy Debug, která všechny E_NOTICE buď zobrazuje nebo loguje, podobně utopistický. Srovnej třeba s patičkou na stránkách http://php.vrana.cz/ ;)
- odin
- Člen | 50
David Grudl napsal(a):
odin napsal(a):
Takze to znamena, ze aby nette nehodilo vyjimku, tak pred vsema funkcema, ktere muzou generovat warning musi byt zavinace?
Uzavíráš funkce, které mohou generovat výjimky, do prázdného
try { } catch()
?
ne to rozhodne ne, to bych tu chybu ignoroval ;) Ale jsou funkce, ktere vraci chybovou hodnotu a vyhazuji warning, cili modelovy priklad:
<?php
if (!mysql_connect('foobar', 'foo', 'bar')) { //zde warning
....
//nejake osetreni chyby. Pokud potrebuju, hlasku si vezmu z get_last_error() nebo mysql_error() nebo neco takovyho
} else {
mysql_select_db('treba')
}
?>
Takze aby to ted prolezlo, tak musim pred mysql_connect napsat @ (i kdyz testuji navratovou hodnotu (a warning nevypisuju), treba tak, jak je to v Dibi (ale toto se pochopitelne netyka jen DB funkci, zeano).
Nebo z opacne strany – problem vidim v tom, ze warning v PHP znamena ledacos – jak runtime potize (treba, ze nejede DB), tak problemy v kodu (nespravny pocet parametru pro funkci). To druhe by si jiste prevod na PHPException zaslouzilo.
- Honza Kuchař
- Člen | 1662
David Grudl napsal(a):
Honza Kuchař napsal(a):
Zajímavá myšlenka, akorát je problém s tou přenositelností kódu. Já opravdu nevím, jestli podpořit nebo odporovat. Ale jako koncept je to opravdu parádní.
Asi jediná možnost je to zkusit nějakou dobu používat a pak se rozhodnout. Na měsíc to zkusím a uvidím.
Teď, když si čtu znova, jak by to fungovalo, jsem pro. Protože pokud tam, kde byl doteď zavináč a kontroluje se návratová hodnota, to bude fungovat i nadále, je to zpětně kompatibilní. Pokud to vyhodilo WARNING, je to zásadní chyba → výjimka je adekvátní. Geniální. :) Doufám, že jsem pochopil správně funkci.
Tedy potřeba si uvědomit, že jakýkoli kód, který předpokládá, že warningy budou potlačeny je špatný. Tedy za mě tento nápad i realizace má ZELENOU. Zvýší to jednoznačně kvalitu kódu.
Nicméně – před lety byl i koncept třídy Debug, která všechny E_NOTICE buď zobrazuje nebo loguje, podobně utopistický. Srovnej třeba s patičkou na stránkách http://php.vrana.cz/ ;)
Jak píšeš. :)
- westrem
- Člen | 398
Ondřej Mirtes napsal(a):
Na jednu stranu je to zajímavý nápad, na druhou stranu je to magie. Magie, která činí kód nepřenositelným. Nechci se ve svých třídách spoléhat na to, že poběží v prostředí Nette. (Konkrétně, že budou někam includovány po zavolání Debug::enable(), který asi toto chování spustí.)
Je to velký zásah do chování jazyka. Jako proof-of-concept pěkné, ale do ostré verze tomu nejspíš podporu nevyjádřím.
Suhlasim, myslienka je to pekna, ale ak by si clovek pisal veci obecne a potom chcel nejaku malu cast nasadit aj mimo prostredia Nette tak by mal problem.
bene napsal(a):
A nešlo by, aby se strict mode choval tak, že bude vyhazovat výjimky? A přidat
$immediateDeath
jako aktuální chování strict mode?Možná jsem blázen ale Notice: Undefined offset… je dle mě chyba a nepřípustná věc. Proto mám zapnutý strict mode.
+1 .. to immediateDeath je pekny napad
- David Grudl
- Nette Core | 8227
odin napsal(a):
ne to rozhodne ne, to bych tu chybu ignoroval ;) Ale jsou funkce, ktere vraci chybovou hodnotu a vyhazuji warning, cili modelovy priklad:
<?php
if (!mysql_connect(‚foobar‘, ‚foo‘, ‚bar‘)) { //zde warning
Mám za to, že programátoři v Nette se snažím podobným warningům automaticky předcházet a tedy rovnou použijí zavináč (což by potlačilo i vyhození PhpException) a poté kontrolují návratovou hodnotu. V tomto směru by se tedy nic nezměnilo.
Naopak by ale vznikla možnost psát kód takto:
try {
mysql_connect('foobar', 'foo', 'bar');
mysql_set_charset('utf8');
mysql_select_db('xxx');
} catch (PhpException $e) {
// nejake osetreni chyby
}
(ano, je to „nový jazyk“)
Mnohem zajímavější je to v kombinaci se skládáním funkcí:
try {
$product = mysql_fetch_assoc(mysql_query('SELECT * FROM products WHERE id=123'));
} catch (PhpException $e) {
...
}
try {
$items = $link->query('SELECT * FROM products')->fetch_all(); // tohle je modelový příklad, mysqli umí vyhazovat mysqli_sql_exception
} catch (PhpException $e) {
...
}
- odin
- Člen | 50
David Grudl napsal(a):
Mám za to, že programátoři v Nette se snažím podobným warningům automaticky předcházet a tedy rovnou použijí zavináč (což by potlačilo i vyhození PhpException) a poté kontrolují návratovou hodnotu. V tomto směru by se tedy nic nezměnilo.
No to je presne to co jsem psal na zacatku. Cili, aby ten kod (dejme tomu kod nejake knihovny) fungoval stejne, tak je potreba pred vsechny funkce, ktere muzou hodit warning dat zavinace (anebo tuhle ficuru vypnout). Proc to tak rozebiram – jsou funkce, ktere warning generuji jen za dobreho pocasi – napr mysql_select_db() – pokud DB neexistuje vrati false, pokud je chyba ve spojeni v DB vrati false a generuje warning. mysql_query() se chova tusim podobne. Coz vede na to, ze treba hodne lidi pise @mysql_connect(), to je ok, ale uz ne @mysql_select_db() protoze to zkratka vetsinou warning negeneruje. Kdo treba pise zavinace pred preg_replace()? ftp_chmod() se myslim chova taky tak nejak podobne debilne.
Problem proste vidim v tom, ze ty warningy jsou pomichane dohromady veci co by mely byt LogicException a RuntimeException a notice. Cili vezmu aplikaci – na test serveru jede, dam na produkcni a prask vyjimka a mrtvo (prestoze by se z toho ta aplikace klidne zvetila). Resp. ve svym kodu si to muzu pohlidat, problem je s knihovnama.
Naopak by ale vznikla možnost psát kód takto:
try { mysql_connect('foobar', 'foo', 'bar'); mysql_set_charset('utf8'); mysql_select_db('xxx'); } catch (PhpException $e) { // nejake osetreni chyby }
Jasne, to chapu, to je to super. Konecne to PHP vypada jako normalni jazyk.
- Honza Kuchař
- Člen | 1662
Vyki napsal(a):
David Grudl napsal(a):
Naopak by ale vznikla možnost psát kód takto
Kdyby to fungovalo takto, sám bych to využil v mnoha projektech. Usnadnilo by to práci. Sice by to byl „nový jazyk“ spojený s Nette, ale ruku na srdce, kdo z vás Nettistů dělá projekty bez Nette?
Projekt celý ne, ale občas se musí kvůli rychlosti nějaký ten bod pro AJAX udělat bez Nette. Ale to jsou výjimky a rozhodně se s tím začátečník nepotká.
- David Grudl
- Nette Core | 8227
odin napsal(a):
…jsou funkce, ktere warning generuji jen za dobreho pocasi – napr mysql_select_db() – pokud DB neexistuje vrati false, pokud je chyba ve spojeni v DB vrati false a generuje warning.
A ruku na srdce, nejsou to právě situace, kdy by výjimka zachránila víc, než opomenutý test návratové hodnoty?
- odin
- Člen | 50
David Grudl napsal(a):
odin napsal(a):
…jsou funkce, ktere warning generuji jen za dobreho pocasi – napr mysql_select_db() – pokud DB neexistuje vrati false, pokud je chyba ve spojeni v DB vrati false a generuje warning.
A ruku na srdce, nejsou to právě situace, kdy by výjimka zachránila víc, než opomenutý test návratové hodnoty?
No nejsou, protoze to tu vyjimku vyhodi jen nekdy (protoze to ten warning generuje jen nekdy). Kdezto ta navrathova hodnota je konzistentne false.
- David Grudl
- Nette Core | 8227
Teoreticky by šlo chování povolovat jen pro některé třídy nebo soubory pomocí anotací.