try... catch en @
1) Hoe gebruik je een try-catch blok? Zet je het try-catch blok alleen om het stukje code heen waar je daadwerkelijk een exception wilt gooien als het misgaat? Of kun je het try-catch blok ook om de complete code van je website heen zetten, zodat alles dus in het try-catch blok staat? De laatste optie is veel makkelijker omdat je dan niet telkens een try-catch blok hoeft te maken en je direct een exception kunt gooien. Alleen ik vraag me af of dit de juiste wijze is en of hier wellicht (performance?)nadelen aan zitten.
2) Je kunt een mogelijke foutmelding onderdrukken door @ voor de functie te zetten, bijvoorbeeld @fopen(). Nu vraag ik me af, als ik de errormeldingen uitschakel voor de gehele website, heeft dit dan hetzelfde effect als @?
Alvast bedankt voor de reacties.
Daarom vind het het gewoon handig om aan het begin van je hele script met try te beginnen, waarna je aan het einde een catch plaatst.
PDO bijv. die gebruikt een PDO-exception. Die kan je als ik het goed heb opvangen in een normale exception:
Maar ook e.v.t in een specifiekere catch:
Gewijzigd op 16/01/2012 08:57:17 door - Ariën -
Maar ik vraag me dus af of dit nog nadelige gevolgen heeft. Als je alles namelijk "evalueert" (try) zou dat dan niet vertragend werken?
Toevoeging op 16/01/2012 09:12:36:
Toevoeging: als je error_reporting uit zet, dan kun je toch nog wel gewoon exceptions throwen? Bijv. if(!fopen('bestand')) throw new Exception('kan bestand niet openen').
Ik ben wel benieuwd hoe je dit mooi kan implementeren in een MVC model, zonder dat je de index staat te vervuilen met try en catches.
Ja, dat klopt. Maar ik denk (ik weet het niet zeker) dat hij nu wel alles wat in het try gedeelte staat gaat evalueren. Het lijkt me dat hij alle code gaat "tryen" omdat alles in het "try" gedeelte staat. Ik kan me voorstellen dat dit vertraging oplevert, maar wellicht zit ik er helemaal naast.
"Ik ben wel benieuwd hoe je dit mooi kan implementeren in een MVC model, zonder dat je de index staat te vervuilen met try en catches."
Als je alles in 1 try-catch blok zet, dan is dat niet heel moeilijk denk ik. Dan zou je gewoon een index maken met een try-catch blok en in de try zet je include 'index2.php' of iets dergelijks. Je index2.php (of hoe je het ook wil noemen) wordt dan je "echte" index en daar hoef je dan geen try-catch meer in te zetten.
Misschien dat iemand het beter weet, maar dit is wat ik begrijp.
In mijn vraag over de implementatie ervan in het MVC-model gaat het mij er niet om hoe ik de try catch implementeer, of je ze nou nest of niet....
Het gaat erop hoe ik dit in de methods implementeer. Een bootstrap zou het beste kunnen zijn, lijkt me?
Als je met index.php en index2.php bezig bent, dan ben je niet echt met MVC bezig.
PHP heeft verschillende ingebouwde Exceptions, waarvan sommige child van elkaar zijn of parent. Daardoor kun je deze mooi uit elkaar halen. Alle Exceptions in PHP kun je hier vinden: http://www.php.net/~helly/php/ext/spl/classException.html
Je ziet dat het in 2 delen is opgesplitst:
1) LogicException
2) RuntimeException
Een LogicException is een exception met fouten in de code en een RuntimeException is een exception met fouten van de gebruiker.
Een voorbeeld hierbij:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
class Registery
{
protected static $values;
public static function set( $label, $value )
{
if( isset(self::$values[$label]) )
throw new InvalidArgumentException(sprintf('[%s] The label(%s) already exists', __CLASS__, $label));
self::$values[$label] = $value;
}
public static function get( $label )
{
if( !isset(self::$values[$label]) )
throw new InvalidArgumentException(sprintf('[%s] The label(%s) does not exists', __CLASS__, $label));
return self::$label;
}
}
try
{
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
{
if( !isset($_POST['name']) )
throw new UnexpectedValueException('Je moet een naam invullen');
}
}
catch( LogicException $e )
{
// een program error
error_log($e->getMessage()); // Iets meer informatie mag natuurlijk wel
}
catch( RuntimeException $e )
{
// een user error
echo $e->getMessage();
}
?>
class Registery
{
protected static $values;
public static function set( $label, $value )
{
if( isset(self::$values[$label]) )
throw new InvalidArgumentException(sprintf('[%s] The label(%s) already exists', __CLASS__, $label));
self::$values[$label] = $value;
}
public static function get( $label )
{
if( !isset(self::$values[$label]) )
throw new InvalidArgumentException(sprintf('[%s] The label(%s) does not exists', __CLASS__, $label));
return self::$label;
}
}
try
{
if( $_SERVER['REQUEST_METHOD'] == 'POST' )
{
if( !isset($_POST['name']) )
throw new UnexpectedValueException('Je moet een naam invullen');
}
}
catch( LogicException $e )
{
// een program error
error_log($e->getMessage()); // Iets meer informatie mag natuurlijk wel
}
catch( RuntimeException $e )
{
// een user error
echo $e->getMessage();
}
?>
Fouten onderdrukken met @ is nooit goed. Deze fouten verschijnen niet als je display_errors uit zet, want dan komt er geen 1 fout meer zichtbaar.
Gewijzigd op 16/01/2012 09:45:22 door Wouter J
Een mooie foutpagina die niet veel relevants aangeeft wanneer debug uit staan en mooi alle fout gerelateerde informatie weergeeft wanneer debug aanstaat.
Verder is try{}catch{} niet echt trager, het is meer dat je php aangeeft: als er nu een fout optreed ga je naar regel ... om het op te vangen.
De try-catch in de bootstrap? En een exception-method oproepen. Of hoort dit niet in de bootstrap?
@Smur f: het is dus niet zo dat als je alles in een try-blok zet, dat ie dan telkens eerst iedere regel gaat evalueren of iets dergelijks? Er gebeurt dus eigenlijk pas iets op het moment dat ie ergens throw new Exception() tegenkomt. Begrijp ik het zo goed? Dus eigenlijk wat Aar ook zegt?
@Aar: hmmm, dat weet ik eigenlijk ook niet..
Gewijzigd op 16/01/2012 09:55:11 door Ozzie PHP
Ozzie PHP op 16/01/2012 09:54:33:
@Wouter: Thanks voor je reactie. Waarom verschillende typen exceptions gebruiken in plaats van 1? Je kan toch in de message aangeven wat er fout gaat?
Het ligt eraan of je ze apart wilt afhandelen?
Misschien wil je exception van PDO juist mailen, of een specifiekere PDO foutmelding geven. Als je echt maar 1 exceptie-foutafhandeling wilt gebruiken. Dan gebruik je toch de normale Exception.
Ozzie PHP:
Als ik dan display_errors en error_reporting op 0 zet, heb ik dan hetzelfde resultaat als wanneer ik @ voor een functie zet?
Ja
Ozzie PHP:
Er gebeurt dus eigenlijk pas iets op het moment dat ie ergens throw new Exception() tegenkomt. Begrijp ik het zo goed? Dus eigenlijk wat Aar ook zegt?
Ja, PHP voert gewoon de code uit, zoals normaal. Alleen mocht hij een throw tegenkomen, wat als het goed is alleen bij fouten gebeurd, dan springt hij over naar de catch.
Ozzie PHP:
Thanks voor je reactie. Waarom verschillende typen exceptions gebruiken in plaats van 1? Je kan toch in de message aangeven wat er fout gaat?
Ik wil niet dat de gebruiker een melding krijgt dat de DB niet werkt. Ik wil dat deze gelogd wordt, zodat ik die in het admin panel o.i.d. kan weergeven.
Ik wil wel dat foutmeldingen als 'geen naam ingevuld' worden weergegeven aan de gebruiker, maar die hoef ik daarna niet meer te zien.
Daarom moet je onderscheid maken tussen runtime en logic exceptions, zodat je deze taken ook mooi kan scheiden.
Op het traagheid niveau, in principe werkt het volgens mij zo dat als er een exception optreed hij dan pas gaat kijken of er op het huidige niveau een catch is en anders verder opgooit.
1) "Ik wil wel dat foutmeldingen als 'geen naam ingevuld' worden weergegeven aan de gebruiker, maar die hoef ik daarna niet meer te zien." Gebruik jij voor dit soort dingen Exceptions? Ik dacht dat je exceptions alleen gebruikt bij hele kritische processen (bijv. database die niet werkt, bestand dat niet kan worden geopend e.d.)
2) De vraag van Aar vind ik ook interessant. "Dan vraag ik me af hoe de implementatie ervan het beste in een MVC model eruit zal zien? De try-catch in de bootstrap? En een exception-method oproepen. Of hoort dit niet in de bootstrap?"
2) Hier heb ik helaas geen verstand van...
Wouter, wat betreft punt 1... ik dacht dat de code stopt als je een Exception gooit. Of zit ik er nu naast? Maar als iemand z'n naam niet invult en de code stopt, dan wordt de view toch ook niet getoond?
Code (php)
Je zou het zeg maar kunnen zien dat als je de exception niet goed opvangt, je try catch die om je site hangt hem opvangt en dan is dus de hele handel een try. In dat geval stopt inderdaad de code op het moment van de exception.
Even een voorbeeldje ter illustratie:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
function test1(){
throw new TrollException();
echo 'hier komen we niet';
}
function test2(){
try{
test1();
}catch(TrollException $e){
echo 'opgevangen in test2';
}
echo 'hier dus wel';
}
try{
test2();
echo 'hier alleen als de exception in test2 al afgehandeld is';
}catch(Exception $e){
echo 'hoge exceptions vangen veel wind';
}
?>
function test1(){
throw new TrollException();
echo 'hier komen we niet';
}
function test2(){
try{
test1();
}catch(TrollException $e){
echo 'opgevangen in test2';
}
echo 'hier dus wel';
}
try{
test2();
echo 'hier alleen als de exception in test2 al afgehandeld is';
}catch(Exception $e){
echo 'hoge exceptions vangen veel wind';
}
?>
Ik hoop dat het wat duidelijk maakt :)
Gewijzigd op 16/01/2012 10:45:31 door Jelle -
Maar dat betekent dus dat als je een try-catch om je hele code heen zet, dat dan je view niet wordt getoond (omdat er na het catch blok niks meer komt). Als je dus gebruikersfouten met try-catch wil afvangen, dan zou je dus telkens kleine try-catch blokjes moeten gebruiken, maar het lijkt me dan handiger om gewoon if-else te gebruiken toch?
Gewijzigd op 16/01/2012 11:01:40 door - Ariën -
Dat ligt er maar net aan hoe jij de applicatie opbouwd, als jij de formulieren met if/elsen gaat controleren is een $formErrors = array() misschien handig. Maar als jij een $form->validate() (bijvoorbeeld) gebruikt kan die heel mooi een exception gooien met een melding, dan heb je de foutafhandeling mooi gescheiden.
$mail = 'smurf@@@phphulp.nl';
$form->validate($mail);
toView($mail);
showView('mail_sent.php');
In dit geval is het mailadres verkeerd. Die validate functie zou dan een Exception throwen, maaaaar... hoe komt ie dan vervolgens weer bij toView() en showView() terecht? Of gaat ie daar gewoon verder na het throwen van de Exception?