oop — как ключевое слово ‘finally’ предназначено для использования в переполнении стека

Итак, я читал об исключениях сегодня в онлайн-руководстве по PHP и понимаю, что мне еще предстоит понять цель или реальную необходимость ключевого слова finally. Я прочитал несколько постов здесь, поэтому мой вопрос немного отличается.

Я понимаю, что мы можем использовать, наконец, таким образом:

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

echo 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

Итак, в этом случае функция hi (); не выполняется и по уважительной причине. Я понимаю, если исключение не обрабатывается
PHP интерпретатор останавливает скрипт. хорошо. Так далеко от того, что я прочитал, наконец, позволяет нам выполнять функцию hi (); даже если
исключение не обрабатывается (хотя я не знаю почему)

Итак, этот я понимаю.

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

выход:

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

Это должно произойти в случае ошибки исключения, а также сообщения «привет» от функции, даже тех, кого я не знаю для этого. Но то, что я не понимаю, даже если мы поймаем LogicException с уловом (LogicException $e) и никаких исключений не было выдано, мы увидели бы выполняемую функцию и увидели бы сообщение «hi». как в этом примере

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

выходы

// Throw logic
// Hi

Итак, мы все еще видим функцию hi() выполняется, хотя у нас нет Uncaught исключений. Почему и зачем это нужно?
Я думал, что блок finally должен использоваться в качестве последнего средства, если исключения не были обнаружены, даже если это не так, тогда зачем его запускать?

14

Решение

независимо от исключения или возврата

исключение

Одно из наиболее распространенных применений, которое я вижу, — это закрытие соединения с базой данных — вы хотите, чтобы это происходило каждый раз (с исключением или без исключения), чтобы у вас не было висячего соединения, которое блокирует сервер баз данных от принятия новых соединений.

Рассмотрим этот псевдокод:

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

Здесь мы всегда будем закрывать соединение с базой данных. Если это обычный запрос, мы закрываем соединение после успеха. Если это ошибочный запрос, то мы все еще закрываем после того, как было сгенерировано исключение.

Вот пример с catch делать некоторые записи.

try {
$database->execute($sql);
} catch (Exception $exception) {
$logger->log($exception->getMessage(), $sql);
throw $exception;
} finally {
$database->close();
}

Это позволит закрыть соединение с или без исключения.

Заметка это поведение отличается в других языках. Например, в .NET, если исключение выдается / перебрасывается из блока catch, тогда блок finally не буду выполнить.

вернуть

Одним из наиболее непонятных поведений является его способность выполнять код после оператора return.

Здесь вы можете установить переменную после возврата функции:

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

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

tryingfinally

но назначение будет тем, что возвращается в try:

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

tryingtrying

и возвращение в конечном итоге отменяет возврат в попытке:

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

echo baz();

в конце концов

нота это поведение было другим в php 5:

finallyfinally
finallyfinally
в конце концов

https://3v4l.org/biO4e

18

Другие решения

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

так что в этом случае:

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

не будет возникать фатальная ошибка из-за заявления
и последний вариант:

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

Наконец, должен содержать любой код, который должен быть выполнен независимо от того, есть ли исключение или нет.

Без наконец:

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

С наконец:

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

Предлагает небольшую очистку в случае, если вам нужно освободить ресурс после того, как функция вернулась.

Это становится еще более полезным в случае, подобном следующему:

 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);
}
}

В этом случае вы можете уменьшить все необходимые fclose звонки перед каждым возвращением в одиночку fclose вызов, который будет выполнен непосредственно перед возвратом метода, но после любого другого кода.

0
По вопросам рекламы [email protected]