try/catch in loop?

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Ozzie PHP

Ozzie PHP

30/12/2013 20:48:26
Quote Anchor link
Hallo,

Ik vraag me eigenlijk af of je een try/catch blok kunt herhalen als ie in de catch terecht komt. En zo ja hoe?

Stel we hebben zoiets als dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

public function foo() {
  // code
  // ...

  try {
    $some_integer = rand(1,50);
    $this->isLowerThanTen($some_integer); // gooit een exception als het getal groter dan 10 is
  } catch (Exception $e) {
    // getal is groter dan 10 -> ga weer terug naar het begin van de try
  }
  // code
  // ...

}

?>

Kan zoiets?
Gewijzigd op 30/12/2013 20:49:14 door Ozzie PHP
 
PHP hulp

PHP hulp

24/11/2024 00:08:53
 
Wouter J

Wouter J

30/12/2013 21:31:04
Quote Anchor link
Goed, wat hadden we ook alweer afgesproken? Een exception was een uitzondering. Is in dit geval het krijgen van een waarde hoger dan 10 een uitzondering voor de methode isLowerThanTen? Nee, wat dat is precies wat hij moet controleren. Als deze method een array krijgt ipv een getal, dan is het een uitzondering.

Dus wat doen we dan? Juistem, we returnen true of false. En wat kunnen we dan gebruiken? Juist, een do-while loop!

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
do {
    $randomInt = rand(1, 50);
}
while ($this->isLowerThanTen($randomInt));
?>


Overigens is dit de meest vreselijke code die er is. Als je niks hogers dan 10 wilt hebben zet je de rand op 10...
Gewijzigd op 30/12/2013 21:32:09 door Wouter J
 
Ozzie PHP

Ozzie PHP

30/12/2013 21:41:08
Quote Anchor link
Haha Wouter, je hebt gelijk :) Het is een ongelukkig voorbeeld.

Maar kun je een try/catch wel in een loop zetten?

Een ander voorbeeldje dan. Wel redelijk onwaarschijnlijk dat het gebeurt, maar het gaat mij ook om het idee of het kan. We maken een random naam aan voor een (tijdelijke) directory. Vervolgens maken we de directory. Mocht de directory al bestaan (die kans is natuurlijk vrijwel nihil) dan wil ik terug naar het begin van de try. Er wordt dan een nieuwe random naam gemaakt en er wordt weer geprobeerd om de directory aan te maken. Kan zoiets?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

public function foo() {
  // code
  // ...

  try {
    $directory = 'foo' . uniqid();
    $this->makeDirectory($directory);
  }
catch (Exception $e) {
    // de directory bestaat al -> ga weer terug naar het begin van de try en probeer het nogmaals
  }
  // code
  // ...

}

?>
Gewijzigd op 30/12/2013 21:41:37 door Ozzie PHP
 
Wouter J

Wouter J

30/12/2013 21:46:54
Quote Anchor link
Ozzie, je zegt het zelf al "het gaat mij ook om het idee of het kan". Als je geen use case kan vinden dan hoeft het ook niet mogelijk te zijn. Als we alles wat wel-mogelijk-had-kunnen-zijn-maar-we-hebben-er-nog-geen-use-case-voor-gevonden in PHP werd geïmplementeerd was die nu 1000 tb en duurde het een uur voordat je script uitgevoerd was.
 
Ozzie PHP

Ozzie PHP

30/12/2013 21:51:35
Quote Anchor link
Wouter, ik ben meer benieuwd of de constructie mogelijk is. De situatie die ik hierboven schets (al is de kans gering) zou kunnen gebeuren. Mijn vraag is dus of je "terug in de code" kunt op de een of andere manier. Je zou in dit voorbeeld bijvoorbeeld de functie opnieuw kunnen aanroepen:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

public function foo() {
  // code
  // ...

  try {
    $directory = 'foo' . uniqid();
    $this->makeDirectory($directory);
  }
catch (Exception $e) {
    return $this->foo();
  }

  // code
  // ...

}

?>

Maar ik vraag me af of dit de enige manier is, of dat er nog andere mogelijkheden zijn.
 
Wouter J

Wouter J

30/12/2013 22:00:59
Quote Anchor link
Je kan ook nog met goto werken, maar dat is nou niet echt een best practise te noemen...

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php
try {
    MakeDir:
    $this->makeDirectory(...);
}
catch (\Exception $e) {
    goto MakeDir;
}

?>
 
Dos Moonen

Dos Moonen

30/12/2013 22:07:10
Quote Anchor link
Ozzie PHP op 30/12/2013 21:51:35:
Wouter, ik ben meer benieuwd of de constructie mogelijk is. De situatie die ik hierboven schets (al is de kans gering) zou kunnen gebeuren. Mijn vraag is dus of je "terug in de code" kunt op de een of andere manier. Je zou in dit voorbeeld bijvoorbeeld de functie opnieuw kunnen aanroepen:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

public function foo() {
  // code
  // ...

  try {
    $directory = 'foo' . uniqid();
    $this->makeDirectory($directory);
  }
catch (Exception $e) {
    return $this->foo();
  }

  // code
  // ...

}

?>

Maar ik vraag me af of dit de enige manier is, of dat er nog andere mogelijkheden zijn.

Dat kan, maar als het te vaak fout gaat krijg je een recurion stack overflow. (Niet genoeg geheugen.)

Een loop zou beter zijn:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

public function foo() {
  // code
  // ...

  while (true) {
    try {
      $directory = 'foo' . uniqid();
      $this->makeDirectory($directory);
      break;
    }
catch (Exception $e) {}
  }

  // code
  // ...

}

?>
 
Ozzie PHP

Ozzie PHP

30/12/2013 22:20:44
Quote Anchor link
@Wouter:

Ah, oké. Ik wist niet dat dat kon. Geinig. Doet me denken aan mijn Commodore 64 tijd :)
Waarom is het geen best practice?

@Dos:

Ziet er goed uit. Waarom zou je bij het aanroepen van de functie een recurion stack overflow krijgen en bij een loop niet? Waarin zit 'm het verschil? En als je jouw oplossing vergelijkt met de "goto" oplossing van Wouter, heeft een van beiden dan de voorkeur (en waarom)?
 
Wouter J

Wouter J

30/12/2013 22:38:31
Quote Anchor link
Ook met een while loop krijg je die error. Maar goed de kans dat het 2x gebeurd is wel heel klein... Vooral als je er nog een usleep(1) in bouwt.

en die van dos heeft altijd de voorkeur. Het gebruik van goto statements betekend het verkeerd indelen van je code (zoals je ook al in de cartoon had kunnen lezen)
 
Ozzie PHP

Ozzie PHP

30/12/2013 22:42:35
Quote Anchor link
Ah oké... maar Dos suggereert dat een loop beter is (zoals ik het lees, omdat dit de kans op een recursion stack overflow verkleint).
 
Dos Moonen

Dos Moonen

30/12/2013 22:49:04
Quote Anchor link
Er is een stack genaamd de Program Counter (ook wel eens Instruction Pointer genoemd) die de adressen bewaard van instructies die uitgevoerd moeten worden na dat een subroutine (functie) uitgevoerd is.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php

$iets
= $bar->foo();

echo $iets;

?>


Dus als je ergens voor de eerste keer $bar->foo() aanroept zal de volgende instructie ($iets =) op die stack geplaatst worden.

Bij de recursive versie zal bij een exception dus de return instructie op die stack gezet worden en vervolgende zal de method foo uitgevoerd worden. Als er telkens een exception gegooit wordt komt dus telkens
die specifieke return instructie boven op de stack terecht.
Op die manier zal je dus na een tijdje niet genoeg geheugen hebben.
Loops hebben dat probleem niet. Als je in C een programma schrijft met "while(1) {}" in de main function zal het CPU vreten maar na eenmaal opgestart is heeft het geen extra geheugen nodig en blijft het draaien tot jij het stopt.
Als je de main functie recursief zou aanroepen gaat het al vrij snel fout: http://stackoverflow.com/questions/2499401/recursive-main-why-does-it-segfault
Gewijzigd op 30/12/2013 22:49:24 door Dos Moonen
 
Ozzie PHP

Ozzie PHP

30/12/2013 23:02:00
Quote Anchor link
Wow, hoe kom jij aan al die kennis Dos? Ik snap je verhaal niet helemaal, maar als ik het goed begrijp stapelt er iets op als je telkens dezelfde functie aanroept, en dat gebeurt niet als je een loop gebruikt? Nou, da's een goede tip om te onthouden! :)
 
Dos Moonen

Dos Moonen

30/12/2013 23:20:18
Quote Anchor link
Het geldt niet alleen recursion. Als je naar een ander stukje code (subroutine, function, method, een andere naam voor het zelfde idee) springt moet je ergens een broodkruimel neergooien om te weten hoe je weer thuis komt.
Een stack overflow komt omdat je niet een oneindig grote stack kunt maken omdat er niet genoeg atomen voor zijn =[ Dat betekend dat er een groote voor de stack gekozen moet worden. De groote van de stack bepaald weer hoeveel functies diep kunt gaan.

Als je stack 5 adressen kan bevatten zal het volgende dus al een stackoverflow opleveren.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php

function1() {
  function2();
}


function2() {
  function3();
}


function3() {
  function4();
}


function4() {
  function5();
}


function5() {
  function6();
}


function6() {
  function7();
}


function1();
?>


Ik heb op school wat (ben absoluut geen expert) spul geleerd over CPU's :p
Gewijzigd op 30/12/2013 23:21:12 door Dos Moonen
 
Ozzie PHP

Ozzie PHP

30/12/2013 23:30:04
Quote Anchor link
>> Als je stack 5 adressen kan bevatten zal het volgende dus al een stackoverflow opleveren.

En hoeveel stack adressen kan iets normaal dan bevatten? 5 lijkt me niet echt veel...
 
Dos Moonen

Dos Moonen

30/12/2013 23:39:27
Quote Anchor link
Oh, je kan gerust 200 levels diep gaan binnen PHP. En PHP is geschreven in C, dus dat zal nog heel wat meer zijn, hoeveel hangt van het OS, start parameters en mogelijk nog wat dingen af.
Bij simpele (recursieve) code hoef je hier vaak geen rekening mee te houden. Maar als de recursie uit de hand begint te lopen zou je je af moeten gaan vragen of het tijd is om te refacteren.
 
Ozzie PHP

Ozzie PHP

30/12/2013 23:49:35
Quote Anchor link
Ah oke...nou, thanks voor de tips in ieder geval :) Ik zal het in m'n achterhoofd houden!
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.