如何查看当前是否有异常,即堆栈正在展开?
在下面的示例中,您将如何实现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块,这反过来使得更容易正确地进行回滚事务。
我在Zend PHP引擎中环顾四周,executor_globals.exception
似乎是我正在寻找的(https://github.com/php/php-src/blob/master/Zend/zend_globals.h)。但是,当我在__destruct()期间检查它时,此值始终为nullptr
。我知道接下来要去哪看?
检查executor_globals.opline_before_exception
已取得一些进展。但是,当捕获到异常时,它不会重置为nullptr
。
/* 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
。
答案 0 :(得分:1)
虽然我不推荐,但我过去已实施过。我的方法(简单地说)是这样的:
实现自定义异常类
class MyException extends Exception {
public static $exceptionThrown = false;
public function __construct($your parameters) {
self::$exceptionThrown = true;
}
}
现在,每个异常都应该是您自己的异常实现,而不是默认的Exception。
class Destroyer {
public function __destruct() {
if(MyException::exceptionThrown() {
Database::rollback();
} else {
Database::commit();
}
}
}