【发布时间】:2011-01-23 21:53:36
【问题描述】:
基本上我有一个自定义异常处理程序。当我处理异常时,我只想让它回显消息并继续脚本。但是我的方法处理异常后,脚本没有继续。
这是 php 的行为还是我的异常处理程序做错了什么?
【问题讨论】:
基本上我有一个自定义异常处理程序。当我处理异常时,我只想让它回显消息并继续脚本。但是我的方法处理异常后,脚本没有继续。
这是 php 的行为还是我的异常处理程序做错了什么?
【问题讨论】:
这是 php 的一种行为。这与set_error_handler() 的不同之处在于,根据set_exception_handler() 上的手册,在调用 exception_handler 后将停止执行。 因此,请确保捕获所有异常,只让那些想要杀死脚本的异常。
这实际上是为什么set_error_handler() 不能很好地与异常配对,而set_exception_handler() 在将所有错误转换为异常时...除非您实际上意味着您的应用程序编码如此严格以至于任何通知或警告都会停止脚本。但至少它可以让您跟踪涉及未设置数组键的调用。
【讨论】:
使用custom exception handler,,您需要在 try/catch 块中捕获异常,并在其中执行您想要的任何处理。
以下是来自The CodeUnit of Craig的例子
try {
$error = 'Throw this error';
throw new Exception($error);
echo 'Never get here';
}
catch (Exception $e)
{
echo 'Exception caught: ', $e->getMessage(), "\n";
}
如果你想捕获并打印任何未处理的异常,你可以设置一个顶级的异常处理程序,比如this example from w3schools(near the bottom of the page)
<?php
function myException($exception){
echo "<b>Exception:</b> " , $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
?>
应该打印:“异常:发生未捕获的异常”
【讨论】:
看下面的代码。它对我有用:
define(BR, "<br/>");
try {
echo "throwing exception" . BR;
throw new Exception("This is exception");
}
catch(Exception $ex) {
echo "caught exception: " . BR . $ex->getMessage() . BR;
}
echo "Keep on going!. ..." . BR;
它打印以下内容:
throwing exception
caught exception:
This is exception
Keep on going!. ...
你说什么? 你能显示你的代码处理程序的代码吗?
【讨论】:
set_exception_handler() 函数创建一个通用 catch 来完全替换某些 try/catch 块,同时具有继续使用脚本的相同效果......这是不可能的.
你可以这样做:
function handleError($errno, $errstring, $errfile, $errline, $errcontext) {
if (error_reporting() & $errno) {
// only process when included in error_reporting
return processError($errno, $errstring);
}
return true;
}
function handleException($exception){
// Here, you do whatever you want with the generated
// exceptions. You can store them in a file or database,
// output them in a debug section of your page or do
// pretty much anything else with it, as if it's a
// normal variable
}
function processError($code, $message){
switch ($code) {
case E_ERROR:
case E_CORE_ERROR:
case E_USER_ERROR:
// Throw exception and stop execution of script
throw new Exception($message, $code);
default:
// Execute exception handler and continue execution afterwards
return handleException(new Exception($message, $code));
}
}
// Set error handler to your custom handler
set_error_handler('handleError');
// Set exception handler to your custom handler
set_exception_handler('handleException');
// ---------------------------------- //
// Generate warning
processError(E_USER_WARNING, 'This went wrong, but we can continue');
// Generate fatal error :
processError(E_USER_ERROR, 'This went horrible wrong');
替代方法:
function handleError($errno, $errstring, $errfile, $errline, $errcontext) {
if (error_reporting() & $errno) {
// only process when included in error_reporting
return handleException(new \Exception($errstring, $errno));
}
return true;
}
function handleException($exception){
// Here, you do whatever you want with the generated
// exceptions. You can store them in a file or database,
// output them in a debug section of your page or do
// pretty much anything else with it, as if it's a
// normal variable
switch ($code) {
case E_ERROR:
case E_CORE_ERROR:
case E_USER_ERROR:
// Make sure script exits here
exit(1);
default:
// Let script continue
return true;
}
}
// Set error handler to your custom handler
set_error_handler('handleError');
// Set exception handler to your custom handler
set_exception_handler('handleException');
// ---------------------------------- //
// Generate warning
trigger_error('This went wrong, but we can continue', E_USER_WARNING);
// Generate fatal error :
trigger_error('This went horrible wrong', E_USER_ERROR);
后一种策略的一个优点是,如果您在函数handleException 中执行$exception->getTrace(),您将获得$errcontext 参数。
这对于某些调试目的非常有用。不幸的是,这仅在您直接从上下文中使用 trigger_error 时才有效,这意味着您不能使用包装函数/方法来别名 trigger_error 函数(因此,如果您愿意,您不能执行类似 function debug($code, $message) { return trigger_error($message, $code); } 的操作跟踪中的上下文数据)。
编辑
我为trigger_error 问题找到了一种dirty 解决方法。
考虑以下代码:
define("__DEBUG__", "Use of undefined constant DEBUG - assumed 'DEBUG'");
public static function handleError($code, $message, $file, $line, $context = false) {
if ($message == __DEBUG__) {
return static::exception(new \Exception(__DEBUG__, E_USER_WARNING));
} else {
if (error_reporting() & $code) {
return static::exception(new \Exception($message, $code));
}
return true;
}
}
public static function handleException($e) {
global $debug;
$code = $e->getCode();
$trace = $e->getTrace();
if ($e->getMessage() == __DEBUG__) {
// DEBUG
array_push($debug, array(
'__TIME__' => microtime(),
'__CONTEXT__' => array(
'file' => $trace[0]['file'],
'line' => $trace[0]['line'],
'function' => $trace[1]['function'],
'class' => $trace[1]['class'],
'type' => $trace[1]['type'],
'args' => $trace[0]['args'][4]
)
));
} else {
// NORMAL ERROR HANDLING
}
return true;
}
使用此代码,您可以使用语句DEBUG; 生成所有可用变量的列表以及任何特定上下文的堆栈跟踪。该列表存储在全局变量$debug 中。您可以将其添加到日志文件、添加到数据库或打印出来。
不过,这是一个非常、非常肮脏的 hack,所以请自行决定使用它。但是,它可以使调试变得更加容易,并允许您为调试代码创建干净的 UI。
【讨论】: