0

Как обойти отсутствие блока finally в PHP?

15

Заголовок: Отсутствие блока finally в PHP до версии 5.5

Описание проблемы:

В PHP до версии 5.5 отсутствует блок finally. В большинстве других языков программирования можно использовать конструкцию:

try {
   // выполнить какие-то действия
} catch(Exception $ex) {
   // обработка ошибки
} finally {
   // очистка ресурсов
}

Однако в PHP нет аналогичного механизма. Это создает определенные трудности для разработчиков, которым необходимо обеспечить корректное завершение выполнения кода и освобождение ресурсов.

Есть ли у кого-нибудь опыт решения этой довольно раздражающей проблемы в языке? Любые советы и обходные пути будут полезны!

5 ответ(ов)

0

Решение, нет. Раздражающая, громоздкая замена – да:

$stored_exc = null;
try {
    // Выполняем код
} catch (Exception $exc) {
    $stored_exc = $exc;
    // Обработка ошибки
}
// "Наконец" здесь, убираем за собой
if ($stored_exc) {
    throw($stored_exc);
}

Не идеально, но должно сработать.

Обратите внимание: В PHP 5.5 наконец-то (извините за каламбур) был добавлен блок finally: https://wiki.php.net/rfc/finally (и на это понадобилось несколько лет... доступен в 5.5 RC почти через четыре года после того, как я опубликовал этот ответ...)

0

Вот моё решение проблемы отсутствия блока finally в PHP. Оно не только предоставляет обходной путь для реализации finally, но также расширяет try/catch, чтобы обрабатывать ошибки PHP (включая фатальные ошибки). Моё решение выглядит следующим образом (PHP 5.3):

_try(
    // некоторый код, который будет нашим блоком try
    function() {
        // этот код ожидается как генерирующий исключение или ошибку PHP
    },

    // некоторый (опциональный) код, который будет нашим блоком catch
    function($exception) {
        // здесь будет поймано исключение
        // ошибки PHP также будут обработаны здесь как ErrorException
    },

    // некоторый (опциональный) код, который будет нашим блоком finally
    function() {
        // этот код выполнится после блока catch и даже после фатальных ошибок
    }
);

Вы можете загрузить решение с документацией и примерами с GitHub - https://github.com/Perennials/travelsdk-core-php/tree/master/src/sys

0

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

Хорошие книги утверждают, что использование блоков finally следует ограничивать только освобождением ресурсов, так как вы не можете быть уверены, что они выполнятся, если произойдёт нечто неприятное. Называть это "раздражающей дырой" — это довольно преувеличенно. Поверьте, много исключительного кода написано на языках без блока finally. 😃

Суть блока finally заключается в том, что он выполняется независимо от того, был ли блок try успешным или нет.

0

Вы можете использовать следующую функцию _try для обработки исключений в PHP. Эта функция принимает три параметра: $try, $catch и $finally. Использование замыканий (closures) позволяет вам передавать любые анонимные функции для выполнения в этих параметрах. $catch является необязательным.

Вот сама функция:

function _try(callable $try, callable $catch, callable $finally = null)
{
    if (is_null($finally))
    {
        $finally = $catch;
        $catch = null;
    }

    try
    {
        $return = $try();
    }
    catch (Exception $rethrow)
    {
        if (isset($catch))
        {
            try
            {
                $catch($rethrow);
                $rethrow = null;
            }
            catch (Exception $rethrow) { }
        }
    }

    $finally();

    if (isset($rethrow))
    {
        throw $rethrow;
    }
    return $return;
}

Примеры использования:

_try(function ()
{
    // Код, который нужно выполнить (try)
}, function ($ex)
{
    // Код обработки исключения (catch)
}, function ()
{
    // Код, который выполнится в любом случае (finally)
});

_try(function ()
{
    // Код, который нужно выполнить (try)
}, function ()
{
    // Код, который выполнится в любом случае (finally)
});

Данная функция правильно обрабатывает исключения различных типов:

  • Когда происходит исключение в $try: оно будет передано в $catch. Сначала выполнится $catch, затем $finally. Если $catch не указан, исключение будет снова брошено после выполнения $finally.
  • Если исключение происходит в $catch: $finally выполнится немедленно, а исключение будет снова брошено после завершения работы $finally.
  • Если исключение происходит в $finally: это приведет к прерыванию стека вызовов, и любые другие исключения, запланированные на повторное выбрасывание, будут проигнорированы.
  • Если исключений не было: функция вернет значение, полученное из $try.

Таким образом, вы можете аккуратно обрабатывать исключения в вашем коде, минимизируя дублирование и сохраняя читабельность.

0

Я только что закончил разработку более элегантного класса Try Catch Finally, который может быть полезен вам. У него есть некоторые недостатки, но с ними можно справиться. Вы можете ознакомиться с кодом по ссылке: gist.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь