Finally finally in PHP 5.5

Read this post in English

Share on:

Cea mai noua versiune de PHP este aproape gata. In momentul cand scriu acest blog, PHP 5.5 este in RC 1.

Cum am mai spus si in blogul anterior, lista de noutati este disponibila la: http://www.php.net/manual/en/migration55.new-features.php

Al doilea feature ca popularitate este “finally”: http://www.php.net/manual/en/language.exceptions.php

Care-i treaba cu “finally“?

Pare un pic confuz, pare un bloc care se executa dupa ce se termina blocul de try catch. Dar ce este nou?

Sa zicem ca avem un bloc try/catch:

PHP 5.x < 5.5:

 1// open resouce
 2$resource = new Resouce();
 3try {
 4    // do stuff with the resouce
 5    $resouce->doStuff();
 6} catch (Exception $e) {
 7    // log exception
 8    syslog(LOG_ERR, $e->getMessage());
 9}
10// release resouce
11unset($resouce);

PHP 5.5

 1// open resouce
 2$resource = new Resouce();
 3try {
 4    // do stuff with the resouce
 5    $resouce->doStuff();
 6} catch (Exception $e) {
 7    // log exception
 8    syslog(LOG_ERR, $e->getMessage());
 9} finally {
10    // release resouce
11    unset($resouce);
12}

Pana aici nu exista nici un motiv pentru care este nevoie de un nou bloc. Am prins exceptia, am facut logging pe ea si am continuat.

Dar sa zicem ca este o resursa si vrem sa o eliberam, iar ulterior sa aruncam exceptia. O varianta ar fi sa eliberam resursa in catch.

Dar mai ramane cazul “fericit”, sa zicem ca trebuie sa o eliberam si atunci.

 1// open resouce
 2$resource = new Resouce();
 3try {
 4    // do stuff with the resouce
 5    $resouce->doStuff();
 6} catch (Exception $e) {
 7    // release resouce
 8    unset($resource);
 9    // perpetuate exception
10    throw $e;
11}

Sa complicam si mai mult, sa zicem ca avem n tipuri de exceptii. Vor rezulta n conditii de catch, plus 1 pentru cazul fericit, iar in toate trebuie sa eliberam resursa. Nu foarte eficient…

O alta varianta este sa stocam exceptia intr-o variabila si, dupa ce am eliberat resursa, sa aruncam si exceptia, daca este cazul.

 1// variable to store the exception
 2$exception = false;
 3
 4// open resouce
 5$resource = new Resouce();
 6try {
 7    // do stuff with the resouce
 8    $resouce->doStuff();
 9} catch (Exception $e) {
10    $exception = $e;
11}
12
13// release resouce
14unset($resource);
15
16if($exception) {
17    throw $exception;
18}

Acesta este unul din modurile in care se realizeaza in prezent. Functioneaza, dar nu evidentiaza faptul ca poate doar vrem sa eliberam resursa si sa ne continuam viata in liniste.

Varianta PHP 5.5

In manualul php.net:

In PHP 5.5 and later, a finally block may also be specified after the catch blocks. Code within the finally block will always be executed after the tryand catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.

De fiecare data cand blocul se executa, indiferent daca se executa cu succes sau nu, finally se va executa. Deci, pentru exemplul:

1try {
2     echo 'Do stuff' . PHP_EOL;
3     throw new Exception('testing');
4} finally {
5     echo 'inside finally' . PHP_EOL;
6}

Outputul va fi:

1Do stuff
2inside finally
3
4Fatal error: Uncaught exception 'Exception' with message 'testing' in...

Daca vrem sa prindem si exceptia:

1try {
2     echo 'Do stuff' . PHP_EOL;
3     throw new Exception('testing');
4} catch (Exception $e) {
5     echo 'do something with the exception' . PHP_EOL;
6} finally {
7     echo 'inside finally' . PHP_EOL;
8}

Outputul va fi:

1Do stuff
2do something with the exception
3inside finally

Si chiar daca luam cazul si mai particular, cand prindem exceptia, apoi o aruncam:

1try {
2     echo 'Do stuff' . PHP_EOL;
3     throw new Exception('testing');
4} catch (Exception $e) {
5     echo 'do something with the exception' . PHP_EOL;
6     throw $e;
7} finally {
8     echo 'inside finally' . PHP_EOL;
9}

Pare ca acum am reusit sa prevenim executia blocului finally? Nu este tocmai asa…

1Do stuff
2do something with the exception
3inside finally
4
5Fatal error: Uncaught exception 'Exception' with message 'testing' in...

Cu alte cuvinte, blocul finally se executa de fiecare data, indiferent de rezultat.