Custom Exception Messages: Best Practices

I wonder how much effort I have to make to format useful debugging information when creating exception messages, or should I just trust the user to provide the correct information or defer collection of information to the exception handler?

I see many people who make their exceptions, for example:

throw new RuntimeException('MyObject is not an array') 

or default exception extensions with custom exceptions that do nothing but change the name of the exception:

 throw new WrongTypeException('MyObject is not an array') 

But this does not provide much debugging information ... and does not force the formatting with the error message. Thus, you can get exactly the same error producing two different error messages ... for example, "Could not connect to database" vs "Could not connect to db"

Of course, if it bubbles up, it will print a stack trace, which is useful, but this does not always tell me everything I need to know, and usually I have to start firing from var_dump () to find out what went wrong and where. .. although this may be somewhat offset by a decent exception handler.

I'm starting to think of something like the code below, where I need an exception thrower to provide the necessary arguments to create the correct error message. I think this may be the way to do this:

  • A minimum level of useful information should be provided.
  • Produces several consistent error messages
  • Templates for exception messages in one place (exception classes), so it’s easier to update messages ...

But I see a drawback in that they are harder to use (you need to look for a definition of an exception) and, thus, can prevent other programmers from using the provided exceptions ...

I would like to comment on this idea and best practices for a consistent flexible structure for exception messages.

 /** * @package MyExceptions * MyWrongTypeException occurs when an object or * datastructure is of the incorrect datatype. * Program defensively! * @param $objectName string name of object, eg "\$myObject" * @param $object object object of the wrong type * @param $expect string expected type of object eg 'integer' * @param $message any additional human readable info. * @param $code error code. * @return Informative exception error message. * @author secoif */ class MyWrongTypeException extends RuntimeException { public function __construct($objectName, $object, $expected, $message = '', $code = 0) { $receivedType = gettype($object) $message = "Wrong Type: $objectName. Expected $expected, received $receivedType"; debug_dump($message, $object); return parent::__construct($message, $code); } } 

....

 /** * If we are in debug mode, append the var_dump of $object to $message */ function debug_dump(&$message, &$object) { if (App::get_mode() == 'debug') { ob_start(); var_dump($object); $message = $message . "Debug Info: " . ob_get_clean(); } } 

Then used as:

 // Hypothetical, supposed to return an array of user objects $users = get_users(); // but instead returns the string 'bad' // Ideally the $users model object would provide a validate() but for the sake // of the example if (is_array($users)) { throw new MyWrongTypeException('$users', $users, 'array') // returns //"Wrong Type: $users. Expected array, received string } 

and we can do something like nl2br in a special exception handler to do something nice for html output.

Read: http://msdn.microsoft.com/en-us/library/cc511859.aspx#

And nothing like that is mentioned, so maybe this is a bad idea ...

+55
php exception
Mar 09 '09 at 23:17
source share
5 answers

I highly recommend the advice of the Krzysztof blog and notice that in your case you seem to be trying to figure out what it calls usage errors.

In this case, it is not a new type that is required to indicate it, but the best error message that caused it. As such, an auxiliary function for:

  • generate text string to place in exception
  • throws all exception and message

This is what is required.

Approach 1 is clearer, but can lead to a slightly more detailed use, 2 - on the contrary, trading terminator syntax for less clarity.

Please note that functions should be extremely safe (they should never cause a self-dependent exception), and not be forced to provide data that is optional for certain reasonable purposes.

Using either of these approaches will simplify the internationalization of the error message later, if necessary.

Stack tracing to a minimum gives you a function and possibly a line number, so you should focus on providing information that is not easy to generate from this.

+30
Mar 10 '09 at 0:51
source share

I will not be distracted by the recommendations regarding the Krzysztof blog, but here is an easy way to create custom exceptions - this is an easy way.

Example:

 <?php require_once "CustomException.php"; class SqlProxyException extends CustomException {} throw new SqlProxyException($errorMsg, mysql_errno()); ?> 

The code behind this (which I borrowed somewhere, I apologize to anyone else)

 <?php interface IException { /* Protected methods inherited from Exception class */ public function getMessage(); // Exception message public function getCode(); // User-defined Exception code public function getFile(); // Source filename public function getLine(); // Source line public function getTrace(); // An array of the backtrace() public function getTraceAsString(); // Formated string of trace /* Overrideable methods inherited from Exception class */ public function __toString(); // formated string for display public function __construct($message = null, $code = 0); } abstract class CustomException extends Exception implements IException { protected $message = 'Unknown exception'; // Exception message private $string; // Unknown protected $code = 0; // User-defined exception code protected $file; // Source filename of exception protected $line; // Source line of exception private $trace; // Unknown public function __construct($message = null, $code = 0) { if (!$message) { throw new $this('Unknown '. get_class($this)); } parent::__construct($message, $code); } public function __toString() { return get_class($this) . " '{$this->message}' in {$this->file}({$this->line})\n" . "{$this->getTraceAsString()}"; } } 
+15
Jul 23 '13 at 10:07 on
source share

See How to create exception hierarchies on the blog of Krzysztof Kvalina, co-author of the Framework Development Guide.

+11
Mar 09 '09 at 23:36
source share

Never, never trust the user to "do the right thing" and include debugging information. If you need information, you need to collect it yourself and save it somewhere where it is available.

Also, as indicated, if it is difficult (er) to do something, users avoid doing it, so again they do not depend on their goodwill and their knowledge of what they need to send.

This thinking implies a method by which you collect information and register it, which involves using var_dump () somewhere.

Also, as Mark Harrison said, a button that makes it easy to send an error message somewhere is fantastic for you and for users. This allows them to report an error. You (as the recipient) get a lot of duplicates, but duplicating information is better than no information.

+3
Mar 10 '09 at 6:31
source share

How many details you add, be sure and

  • simplify cutting and pasting it all, or
  • there is a button that will report an error for them
-one
Mar 09 '09 at 23:23
source share



All Articles