В __destruct (), как вы можете увидеть, находится ли исключение в данный момент в полете?

Как я могу узнать, находится ли исключение в данный момент в полете, то есть стек раскручивается?

В приведенном ниже примере, как бы вы реализовали isExceptionInFlight()?

<?php

class Destroyer
{
function __destruct()   {
if (isExceptionInFlight()) {
echo 'failure';
} else {
echo 'success';
}
}
}

function isExceptionInFlight() {
// ?????
}

function createAndThrow()
{
$var = new Destroyer;
throw new \Exception;
}

createAndThrow();

Целью этого было бы реализовать D scope заявление, которое доступно в виде библиотеки на нескольких других языках. Это позволяет избавиться от вложенных блоков try-catch, что, в свою очередь, упрощает правильное выполнение транзакций с откатами.

Addendum1:

Я посмотрел в Zend PHP Engine и executor_globals.exception кажется то, что я ищу (https://github.com/php/php-src/blob/master/Zend/zend_globals.h). Однако это значение всегда nullptr когда я проверяю это во время __destruct (). Есть идеи, где мне искать дальше?

Addendum2:

инспектирование executor_globals.opline_before_exception привело к некоторому прогрессу. Однако это не сбрасывается на nullptr когда исключение было поймано.

Addendum3:

Я нашел следующий код (строка 135)

/* Make sure that destructors are protected from previously thrown exceptions.
* For example, if an exception was thrown in a function and when the function's
* local variable destruction results in a destructor being called.
*/
old_exception = NULL;
if (EG(exception)) {
if (EG(exception) == object) {
zend_error_noreturn(E_CORE_ERROR, "Attempt to destruct pending exception");
} else {
old_exception = EG(exception);
EG(exception) = NULL;
}
}
zend_call_method_with_0_params(&obj, object->ce, &destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
if (old_exception) {
if (EG(exception)) {
zend_exception_set_previous(EG(exception), old_exception);
} else {
EG(exception) = old_exception;
}
}

Это, кажется, активно НЕ ПРЕДОТВРАЩАЕТ меня делать то, что я хочу, и объясняет, почему executor_globals.exception всегда nullptr,

2

Решение

Хотя я не рекомендую, я реализовал это в прошлом. Мой подход был (проще говоря) так:

Реализуйте пользовательский класс Exception

class MyException extends Exception {
public static $exceptionThrown = false;

public function __construct($your parameters) {
self::$exceptionThrown = true;
}

}

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

class Destroyer {
public function __destruct() {
if(MyException::exceptionThrown() {
Database::rollback();
} else {
Database::commit();
}
}
}
1

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

Других решений пока нет …

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