ʎɹnɔɹǝW
Por lo tanto, he estado leyendo sobre las excepciones hoy en el manual en línea de PHP y me doy cuenta de que todavía tengo que entender el propósito o la necesidad real de la palabra clave finalmente. He leído algunas publicaciones aquí, por lo que mi pregunta es ligeramente diferente.
Entiendo que podemos usar finalmente de esta manera:
function hi(){
return 'Hi';
}
try {
throw new LogicException("Throw logic \n");
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
}
echo hi();
producción:
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
Entonces, en este caso la función hi(); no se está ejecutando y por una buena razón. Entiendo que si no se maneja la excepción, el intérprete de php detiene el script. bien. Lejos de lo que leí, finalmente nos permite ejecutar la función hi(); incluso si no se maneja la excepción (aunque no sé por qué)
Entonces, este lo entiendo.
try {
throw new LogicException("Throw logic \n");
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
}finally{
echo hi();
}
producción:
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
Este debe ser el error de excepción, así como el mensaje ‘hola’ de la función, incluso aquellos que no conozco ningún uso para esto. Pero lo que no entiendo es esto, incluso si captamos el LogicException
con pestillo (LogicException $e)
y no se lanzaron excepciones aún veríamos que la función se está ejecutando, y veríamos el mensaje ‘hola’. como en este ejemplo
try {
throw new LogicException("Throw logic \n");
} catch (LogicException $e) {
echo $e->getMessage();
}finally{
echo hi();
}
salidas
// Throw logic
// Hi
Entonces, todavía vemos la función. hi()
ejecutado a pesar de que no tenemos excepciones no detectadas. ¿Por qué y cuál es el uso de esto? Pensé que el bloque finalmente se usaría como último recurso en caso de que no se detectaran las excepciones, incluso si ese no fuera el caso, ¿por qué se usa para ejecutarlo?
jeff puckett
finally
ejecuta cada*† tiempo
Independientemente de errores, excepciones o incluso return
declaraciones, la finally
se ejecutará un bloque de código.
*Va a no correr si el try
o catch
los bloques se ejecutan die
/exit
.
Excepción
Un uso común que veo es cerrar una conexión de base de datos en un trabajador de larga ejecución: desea que esto suceda cada vez (con o sin excepción) para que no termine con una conexión colgante que bloquee el servidor de la base de datos para que no acepte nuevas conexiones. .
Considere este pseudo-código:
try {
$database->execute($sql);
} finally {
$database->close();
}
Aquí siempre cerraremos la conexión a la base de datos. Si es una consulta normal, cerramos la conexión después del éxito y el script continuará ejecutándose.
Si se trata de una consulta errónea, aún cerramos después de que se haya lanzado la excepción, y la excepción no detectada hará que la secuencia de comandos se detenga.
He aquí un ejemplo con catch
haciendo algo de registro.
try {
$database->execute($sql);
} catch (Exception $exception) {
$logger->error($exception->getMessage(), ['sql' => $sql]);
throw $exception;
} finally {
$database->close();
}
Esto hará que cierre la conexión con o sin excepción.
Devolver
Uno de los comportamientos más oscuros es su capacidad para ejecutar código después de una declaración de devolución.
Aquí puede establecer una variable después de que la función haya regresado:
function foo(&$x)
{
try {
$x = 'trying';
return $x;
} finally {
$x = 'finally';
}
}
$bar="main";
echo foo($bar) . $bar;
tratando finalmente
pero una asignación será lo que se devuelva en try:
$bar = foo($bar);
echo $bar . $bar;
tratando
y volver en el finalmente anula el regreso en el intento:
function baz()
{
try {
return 'trying';
} finally {
return 'finally';
}
}
echo baz();
finalmente
Nota este comportamiento era diferente en php 5:
finalmentefinalmente
finalmentefinalmente
finalmente
Rentabilidad excepcional
Puede hacer que parezca que lanza 2 excepciones para que surjan al mismo tiempo:
try {
throw new Exception('try');
} finally {
throw new Exception('finally');
}
Fatal error: Uncaught Exception: try in /in/2AYmF:4 Stack trace: #0 {main} Next Exception: finally in /in/2AYmF:6 Stack trace: #0 {main} thrown in /in/2AYmF on line 6 Process exited with code 255.
Pero realmente no puede detectar la “primera” excepción que conozco para hacer algo divertido en tiempo de ejecución:
try {
try {
throw new Exception('try');
} finally {
throw new Exception('finally');
}
} catch (Exception $exception) {
echo 'caught ' . $exception->getMessage();
}
atrapado finalmente
* Morir
Si usted exit
o die
entonces el finally
el bloque no se ejecutará.
try {
echo "trying";
die;
} finally {
echo "finally";
}
echo "end";
difícil
† Fallo de hardware
Finalmente, debe comprender que el finally
block no se ejecutará si alguien desconecta el enchufe de su servidor 😉 y, aunque no lo he probado, espero que el agotamiento de la memoria también lo omita.
-
Lo entiendo ahora, pero los casos de uso parecen muy raros. En su ejemplo, por ejemplo, aún podría cerrar la base de datos antes de que
throw
declaración, y hubiera logrado lo mismo.– ʎɹnɔɹǝW
13 de enero de 2017 a las 8:54
-
@mvrht: Por supuesto, podría cerrar la conexión DB antes del
throw
declaración sin que usandofinally
pero el punto es en ese caso: en primer lugar, tal vez no capte cada excepción pero solo un cierto tipo, entonces no llegas alclose()
llame para otras excepciones. En segundo lugar, incluso si detecta todas las excepciones, necesita una línea de código duplicada en algún lugar (al final detry
bloque o despuéscatch
bloque) para llamarclose()
. Poner esa llamada en elfinally
bloque, debe escribirlo solo una vez y se ejecuta en todos los casos (si ocurre una excepción o no, si se detecta o no).– dwytrykus
15 de febrero de 2017 a las 10:57
-
Si alguien está preguntando,
finally
se ejecuta cada vez excepto cuando hay unexit()
/die()
dentro de probar o el captura bloque (el que se ejecuta)– Simo Pelle
11 de junio de 2020 a las 21:17
-
@Foxel buena idea! Incluiré esto en mi respuesta 🙂
–Jeff Puckett
11 de junio de 2020 a las 21:24
-
@James 😂 debemos estar cortados por la misma tijera, porque eso además me vuelve loco dondequiera que lo vea, así que intencionalmente lo dejé para que fuera un idiota. pero ahora me doy cuenta de la inmadurez de mis caminos y he agregado dos referencias apropiadas ⛪
–Jeff Puckett
19 de noviembre de 2020 a las 1:34
Finalmente, debe contener cualquier código que deba ejecutarse independientemente de si hay una excepción o no.
Sin finalmente:
try {
$handle = fopen("file.txt");
//Do stuff
fclose($handle);
return something;
} catch (Exception $e) {
// Log
if (isset($handle) && $handle !== false) {
fclose($handle);
}
}
con finalmente:
try {
$handle = fopen("file.txt");
return something;
} catch (Exception $e) {
// Log
} finally {
if (isset($handle) && $handle !== false) {
fclose($handle);
}
}
Ofrece un poco de orden en el caso de que necesite liberar un recurso después de que una función haya regresado.
Esto se vuelve aún más útil en un caso como el siguiente:
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);
}
}
En este caso, puede reducir todos los requisitos fclose
llamadas antes de cada regreso a una sola fclose
llamada que se ejecutará justo antes de que el método regrese pero después de cualquier otro código.
myxaxa
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
entonces en este caso:
try {
throw new LogicException("Throw logic \n"); -> LogicException thrown
} catch (InvalidArgumentException $e) { -> LogicException not catched
echo $e->getMessage();
}finally{
echo hi(); -> code executed
die();
}
no se generará ningún error fatal, debido a la declaración y la última variación:
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
}
Yevgeni Afanasyev
Hice una pequeña prueba unitaria para mostrar cómo funciona
$a="a";
try {
$a .= 'b';
} catch (Exception $ex) {
$a .= 'e';
} finally {
$a .= 'f';
}
$a .= 'x';
$this->assertSame('abfx', $a);
$a="a";
try {
$a .= 'b';
throw new Exception();
$a .= '1';
} catch (Exception $ex) {
$a .= 'e';
} finally {
$a .= 'f';
}
$a .= 'x';
$this->assertSame('abefx', $a);
$a="a";
try {
try {
$a .= 'b';
throw new Exception();
$a .= '1';
} catch (Exception $ex) {
$a .= 'e';
throw $ex;
$a .= '2';
} finally {
$a .= 'f';
}
$a .= 'x';
} catch (Exception $ex) {
$a .= 'z';
}
$this->assertSame('abefz', $a);
¿Qué versión de PHP estás usando? Verdadero
finally
la funcionalidad no se agregó hasta PHP 5.5.– Alec Gordon
12 de enero de 2017 a las 15:29
@AlecGordon php 7.0.1
– ʎɹnɔɹǝW
12 de enero de 2017 a las 15:33
Oh, eso es extraño entonces. De acuerdo a este análisis el bloque finalmente debe imprimirse antes de la excepción no detectada.
– Alec Gordon
12 de enero de 2017 a las 15:36
Código en
finally
se ejecuta después de todo el código entry
+catch
.– Germán Lashevich
12 de enero de 2017 a las 16:37