web-dev-qa-db-fra.com

Comment le mot-clé «enfin» doit-il être utilisé en PHP?

Donc, j'ai lu aujourd'hui sur les exceptions dans le manuel en ligne PHP, et je me rends compte que je n'ai pas encore compris le but ou la réelle nécessité du mot-clé finally. J'ai lu quelques articles ici, donc ma question est légèrement différente.

Je comprends que nous pouvons enfin utiliser de cette façon:

function hi(){
    return 'Hi';
}


try {
    throw new LogicException("Throw logic \n");
} catch (InvalidArgumentException $e) {
    echo $e->getMessage(); 
}

echo hi();

production:

Fatal error:  Uncaught LogicException: Throw Logic in C:\Users\...a.php:167
Stack trace:
#0 {main}
  thrown in C:\Users\...a.php on line 167

Donc, dans ce cas, la fonction hi (); n'est pas en cours d'exécution et pour une bonne raison. Je comprends que si l'exception n'est pas gérée, l'interpréteur php arrête le script. bien. Loin de ce que j'ai lu, nous permet enfin d'exécuter la fonction hi (); même si l'exception n'est pas gérée (même si je ne sais pas pourquoi)

Donc, celui-ci, je le comprends.

try {
    throw new LogicException("Throw logic \n");
} catch (InvalidArgumentException $e) {
    echo $e->getMessage(); 
}finally{
    echo hi();
}

production:

Hi
Fatal error:  Uncaught LogicException: Throw Logic in C:\Users\...a.php:167
Stack trace:
#0 {main}
  thrown in C:\Users\...a.php on line 167

Cela devrait être le cas de l'erreur d'exception ainsi que du message "salut" de la fonction, même ceux dont je ne connais aucune utilisation. Mais ce que je ne comprends pas, même si nous interceptons le LogicException avec catch (LogicException $e) Et qu'aucune exception n'a été levée, nous verrions la fonction s'exécuter et nous verrions le "salut" message. comme dans cet exemple

try {
    throw new LogicException("Throw logic \n");
} catch (LogicException $e) {
    echo $e->getMessage(); 
}finally{
    echo hi();
}

les sorties

// Throw logic 
// Hi

Ainsi, nous voyons toujours la fonction hi() exécutée même si nous n'avons pas d'exceptions Uncaught. Pourquoi et à quoi cela sert-il? Je pensais que le bloc finalement devait être utilisé en dernier recours au cas où les exceptions ne seraient pas interceptées, même si ce n'était pas le cas, alors pourquoi est-il utilisé pour l'exécuter?

22
ʎɹnɔɹǝW

finally s'exécute à chaque fois

quelle que soit l'exception ou le retour

exception

Une utilisation courante que je vois est la fermeture d'une connexion à une base de données chez un travailleur de longue durée - vous voulez que cela se produise à chaque fois (avec ou sans exception) afin de ne pas vous retrouver avec une connexion pendante qui empêche le serveur de base de données d'accepter de nouvelles connexions .

Considérez ce pseudo-code:

try {
   $database->execute($sql);
} finally {
   $database->close();
}

Ici, nous fermerons toujours la connexion à la base de données. S'il s'agit d'une requête normale, nous fermons la connexion après le succès. S'il s'agit d'une requête erronée, nous fermons toujours après que l'exception a été levée.

Voici un exemple avec catch faisant un peu de journalisation.

try {
   $database->execute($sql);
} catch (Exception $exception) {
   $logger->error($exception->getMessage(), ['sql' => $sql]);
   throw $exception;
} finally {
   $database->close();
}

Cela lui fera fermer la connexion avec ou sans exception.

Remarque ce comportement est différent dans les autres langues. Par exemple, dans .NET si une exception est levée/relancée à partir du bloc catch, le bloc finally ne le sera pas s'exécutera.

revenir

L'un des comportements les plus obscurs est sa capacité à exécuter du code après une instruction de retour.

Ici, vous pouvez définir une variable après le retour de la fonction:

function foo(&$x)
{
    try {
        $x = 'trying';
        return $x;
    } finally {
        $x = 'finally';
    }
}

$bar = 'main';
echo foo($bar) . $bar;

essayer enfin

mais une affectation sera ce qui est retourné dans try:

$bar = foo($bar);
echo $bar . $bar;

essayer

et le retour dans le remplace finalement le retour dans l'essai:

function baz()
{
    try {
        return 'trying';
    } finally {
        return 'finally';
    }
}

echo baz();

enfin

note ce comportement était différent en php 5:

enfin
enfinfinalement
enfin

https://3v4l.org/biO4e

26
Jeff Puckett
try {
    throw new LogicException("Throw logic \n"); -> LogicException thrown
} catch (InvalidArgumentException $e) { -> LogicException not catched
    echo $e->getMessage(); 
}finally{
    echo hi(); -> code executed. "Hi" printed out
}

LogicException is here -> Fatal error

donc dans ce cas:

try {
    throw new LogicException("Throw logic \n"); -> LogicException thrown
} catch (InvalidArgumentException $e) { -> LogicException not catched
    echo $e->getMessage(); 
}finally{
    echo hi(); -> code executed
    die();
}

aucune erreur fatale ne sera levée, à cause de la déclaration et de la dernière variation:

try {
    throw new LogicException("Throw logic \n"); -> LogicException thrown
} catch (InvalidArgumentException $e) { -> LogicException not catched
    echo $e->getMessage(); 
} catch (LogicException $e) { -> LogicException catched
    echo $e->getMessage(); 
}finally{
    echo hi(); -> code executed
}
1
myxaxa

Enfin, devrait contenir tout code qui doit être exécuté, qu'il y ait une exception ou non.

Sans finalement:

try {
   $handle = fopen("file.txt");
   //Do stuff
   fclose($handle);
   return something;
} catch (Exception $e) {
   // Log
   if (isset($handle) && $handle !== false) {
      fclose($handle);
   }     
}

Avec enfin:

try {
   $handle = fopen("file.txt");
   return something;
} catch (Exception $e) {
   // Log
} finally {
   if (isset($handle) && $handle !== false) {
      fclose($handle);
   }     
}

Offre un peu de désencombrement dans le cas où vous devez libérer une ressource après le retour d'une fonction.

Cela devient encore plus utile dans un cas comme celui-ci:

 try {
     $handle = fopen("file.txt");
     if (case1) { return result1; }  
     if (case2) { return result2; }
     if (case3) { return result3; }
     if (case4) { return result4; }

 } finally {
     if (isset($handle) && $handle !== false) {
          fclose($handle);
       }    
 }

Dans ce cas, vous pouvez réduire tous les appels fclose requis avant chaque retour à un seul appel fclose qui sera exécuté juste avant le retour de la méthode mais après tout autre code.

0
apokryfos