I am looking to get some advice on best practice for throwing exceptions and catching them. I am using a 3rd party library for connecting to Amazon mws API. This library already throws exceptions which I am catching within a function.
My question is, should this function pass the exception onto the main script by using a try-catch? e.g.
function myFunction() {
try {
$obj = new Object();
$obj->makeCall();
return $obj->getData();
} catch (Exception $ex) {
throw new Exception('There was a problem with the library '.$ex->getMessage());
}
}
then in the main script;
try {
//make the call
$response = myFunction();
} catch (Exception $e){
//log error
$logger->error("log error");
}
If you are catching the exception in the main script, you don't need to catch it in your function myFunction until you need to do some processing in your function.
The control will return to the exception being catched in the main script if any of it's children or children's children and so on throw an exception.
I am using this script here and it does not always want to connect to the server I set it to. When it doesn't, it'll show an error "Failed to receive status". I'm wondering how can I test to see if this happens and put it into an if statement?
For example:
if (isError) return false;
Here is the part which checks for the error or not in the script:
if( !$Data )
{
throw new MinecraftQueryException( "Failed to receive status." );
}
Just use try ... catch block. But make sure you are logging the exception message. It'll be helpful for future investigation.
try
{
$Query = new MinecraftQuery( );
// .. do mine craft connection
$Query->Connect( '...', 25565 );
print_r( $Query->GetInfo( ) );
} catch(MinecraftQueryException $mqe){
// log $mq->getMessage() for future investigation
return false;
}
You'll want to surround the Connect call inside a try/catch block in order to catch the exception, and then put the failure code inside the catch block. You can read more about exceptions in the PHP manual:
try {
$query->Connect();
} catch(MinecraftQueryException $exception) {
return false;
}
I currently handle errors during AJAX requests in a manner similar to this:
try {
// code
if (some_error_condition) {
throw new \Exception('error');
}
// other code
if (some_other_error_condition) {
throw new \Exception('other error');
}
// more code
$response = array(
'success' => TRUE,
'data' => 'stuff here'
);
} catch (Exception $e) {
$response = array(
'success' => FALSE,
'error' => $e->getMessage()
);
}
header('Content-Type: application/json');
echo json_encode($response);
My question is: is there a better way to handle multiple possible error conditions than this, while still adhering to DRY principles? I think this method is much cleaner and easier to follow than giant nested if/else messes, but it's a little reminiscent of goto code.
Perhaps an OOP way?
it is completely valid solution for me, except you could use different exception classes for your exception and encapsulate actual logic in some object, like
class Handler {
//this function executes code and throws exception - no error handling logic.
public static function doSomeCode() {
(...)
return $response;
}
}
try {
$response = Handler::doSomeCode();
renderResponse();
} catch (SomeError $e) {
$err = 'some error';
renderError($err);
} catch (Exception $e) {
header('500 Internal Server Error'); //this is pseudo code!
}
your exception classes (except generic Exception) could handle rendering errors, Exception class would trigger 500 (it should never happend). This way you separate actual code execution from error handling, and with proper exceptions object model dont repeat yourself with error handling.
basically i have a custom exception handler. When i handle an exception, i just want it to echo the message and continue the script. But after my method handles the exception, the script doesnt continue.
Is this a behaviour of php or is my exception handler doing something wrong?
This is a behavior of php. This differs from set_error_handler() in that, according to the manual on set_exception_handler(), Execution will stop after the exception_handler is called. Therefore, ensure you catch all exceptions, letting only those you want to kill your script through.
This is actually why set_error_handler() doesn't pair well with exceptions and set_exception_handler() when converting all errors to exceptions... unless you actually mean your application to be so strictly coded that any notice or warning halts the script. But at least it gives you a trace on that call involving an unset array key.
With a custom exception handler, you'll want to catch the exception in a try/catch block and do whatever handling you want in there.
The following is the example from 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";
}
If you want to catch and print any unhandled exception, you can set a top level exception handler like 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');
?>
should print: "Exception: Uncaught Exception occurred"
Look at the following code. it worked for me:
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;
it prints the following:
throwing exception
caught exception:
This is exception
Keep on going!. ...
What do you say ?
Can you show the code of your code handler ?
You could do this :
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');
Alternate approach :
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);
An advantage of the latter strategy, is that you get the $errcontext parameter if you do $exception->getTrace() within the function handleException.
This is very useful for certain debugging purposes. Unfortunately, this works only if you use trigger_error directly from your context, which means you can't use a wrapper function/method to alias the trigger_error function (so you can't do something like function debug($code, $message) { return trigger_error($message, $code); } if you want the context data in your trace).
EDIT
I've found one dirty workaround for the trigger_error problem.
Consider the following code :
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;
}
With this code, you can use the statement DEBUG; to generate a list of all available variables and a stack trace for any specific context. This list is stored in the global variable $debug. You can add it to a log file, add it to a database or print it out.
This is a VERY, VERY dirty hack, though, so use it at your own discretion. However, it can make debugging a lot easier and allows you to create a clean UI for your debug code.
I'd like to use an exception for error handling in a part of my code but if the code should fail, I would like the script to continue. I want to log the error though. Can someone please help me figure this out?
try{
if($id == 4)
{
echo'test';
}
}
catch(Exception $e){
echo $e->getMessage();
}
echo'Hello, you should see me...'; <------ I never see this.. No errors, just a trace.
You have to catch the exception :
// some code
try {
// some code, that might throw an exception
// Note that, when the exception is thrown, the code that's after what
// threw it, until the end of this "try" block, will not be executed
} catch (Exception $e) {
// deal with the exception
// code that will be executed only when an exception is thrown
echo $e->getMessage(); // for instance
}
// some code, that will always be executed
And here are a couple of things you should read :
Exceptions in the PHP manual
Exceptional PHP: Introduction to Exceptions
In the code that is calling the code that may throw an Exception do
try {
// code that may break/throw an exception
echo 'Foo';
throw new Exception('Nothing in this try block beyond this line');
echo 'I am never executed';
throw new CustomException('Neither am I');
} catch(CustomException $e) {
// continue here when any CustomException in try block occurs
echo $e->getMessage();
} catch(Exception $e) {
// continue here when any other Exception in try block occurs
echo $e->getMessage();
}
// script continues here
echo 'done';
Output will be (adding line breaks for readability):
'Foo' // echoed in try block
'Nothing in this try block beyond this line' // echoed in Exception catch block
'done' // echoed after try/catch block
Try/Catch Blocks may also be nested. See Example 2 in the PHP Manual page linked above:
try{
try {
throw new Exception('Foo');
echo 'not getting here';
} catch (Exception $e) {
echo $e->getMessage();
}
echo 'bar';
} catch (Exception $e) {
echo $e->getMessage();
}
echo 'done';
'Foo' // echoed in inner catch block
'bar' // echoed after inner try/catch block
'done' // echoed after outer try/catch block
Further reading at DevZone:
http://devzone.zend.com/node/view/id/666
http://devzone.zend.com/article/679-Exceptional-Code---PART-2
http://devzone.zend.com/node/view/id/652
http://devzone.zend.com/article/653-PHP-101-PART-12-BUGGING-OUT---PART-2