在 __destruct() 中,如何查看当前是不是存在异常?
Posted
技术标签:
【中文标题】在 __destruct() 中,如何查看当前是不是存在异常?【英文标题】:In __destruct(), how can you see if an exception is currently in flight?在 __destruct() 中,如何查看当前是否存在异常? 【发布时间】:2016-01-16 22:46:33 【问题描述】:如何查看当前是否存在异常,即堆栈正在展开?
在下面的示例中,您将如何实现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 块,从而更容易正确地执行回滚事务。
附录1:
我查看了 Zend PHP 引擎,executor_globals.exception
似乎就是我正在寻找的东西 (https://github.com/php/php-src/blob/master/Zend/zend_globals.h)。但是,当我在 __destruct() 期间检查它时,此值始终为 nullptr
。知道我接下来应该看哪里吗?
附录2:
检查executor_globals.opline_before_exception
取得了一些进展。但是,当异常被捕获时,它不会重置为nullptr
。
附录3:
我找到了following code (line 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
。
【问题讨论】:
【参考方案1】:虽然我不推荐,但我过去已经实现了。我的方法(简单地说)是这样的:
实现自定义异常类
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();
【讨论】:
如果这个异常被捕获了怎么办?MyException::exceptionThrown
不会仍然是 true
,即使它已被解决?
是的。就像我说的,我真的不推荐这种方法,因为有很多框架更完整。但是在使用该代码时,我比较新手,我喜欢使用 HTTP 失败之类的异常。在使用的时候,我只遇到过一次捕获异常的问题,所以我只是在catch块里面加了一个“MyException::$exceptionThrown = false”。由于我没有类似的麻烦,所以我就让它过去了。以上是关于在 __destruct() 中,如何查看当前是不是存在异常?的主要内容,如果未能解决你的问题,请参考以下文章
在php中实现Serializable接口时正确调用__destruct方法?
PHP中的11个魔术方法总结:__construct,__destruct__call等