Do all PHP Exceptions have 'trace', 'message' and 'code' properties? - php

I have to write a log class that logs the data coming from an exception. To make things simpler, I wanted to know if it is okay to retrieve data inside the 'trace' array and extend this by adding 'message' and 'code' properties of the exception instance in PHP. But I am not sure if all thrown exception in PHP are guaranteed to have at least these three properties ('trace', 'message' and 'code'). Also suggest if there is a better way to log things.

Firstly it's better to use code already proven to be good. PHP community widely use Monolog library check it. If you still want to write your own logger you should stick to PSR-3 rules
Answering your question. PHP object thrown must be an instance of the Exception class or a subclass of Exception.
But you if you look at constructor of an Exception
public function __construct($message = null, $code = 0, Exception $previous = null);
You can throw empty exception.But there will be always code, file, trace and code. Code and Message can be empty.
You can read more about it on http://php.net/manual/en/language.exceptions.php

Related

Writing functions that deal with exceptions

Building upon a question I already asked regarding exceptions, I fear that I might be writing php functions wrong then, or abusing the use of exceptions. The reason I say this, is because if custom exceptions are to be caught using try/catch blocks then the following function:
public function get_specific_page($page) {
if (!is_array( $this->_page )){
throw new AisisCore_Template_TemplateException( "<div class='error'>Trying to get a property from a non array.</div>" );
}
return $this->_page[$page];
}
Would then be called such as:
try{
get_specific_page($page);
}
catch(Exception $e){
echo $e->getMessage();
}
The problem with this approach is that I have many functions that are written like this, either checking to see if a file exists, throwing an error. Checking to see if a value is set in an array, throwing an error and my issue is that the file which deals with these function calls may become over loaded with try catch.....
So my question is, how would I better write functions like this so that I don't have php files over loaded with try catch statements, yet still be able to have y own custom functions.
Is it as obvious as writing the try catch inside the function it's self?
The reason I ask, if because I am use to working with fameworks and in companies where we write our functions as you see above. How ver I have worked with code bases that have tons of these functions and I dont see half the files that are useing them doing a bunch of try catches...
Update:
I was looking through zend source to better understand exceptions and came across this:
public function setMessage($messageString, $messageKey = null)
{
if ($messageKey === null) {
$keys = array_keys($this->_messageTemplates);
foreach($keys as $key) {
$this->setMessage($messageString, $key);
}
return $this;
}
if (!isset($this->_messageTemplates[$messageKey])) {
require_once 'Zend/Validate/Exception.php';
throw new Zend_Validate_Exception("No message template exists for key '$messageKey'");
}
$this->_messageTemplates[$messageKey] = $messageString;
return $this;
}
You can see how they throw a new exception message near the bottom, this function is not called by doing:
try{}catch(){}
yet when it throws an exception, there is no issue with "uncaught exception with message"
In my opinion, your approach is correct in general. However, a few notes:
You should refrain from using HTML formatting in exception messages. Generally, you don't know how the exception that you throw will be handled. For example, an exception handler could just write the message to a log file (you don't want HTML formatting then), present it to the user in a special error view (in which case the view itself should contain the HTML formatting), or simply ignore it (no need for formatting then, anyway).
Catch only exceptions that you can handle. If you know that your function throws an AisisCore_Template_TemplateException, you should just catch that exception and let all other exceptions bubble up to an exception handler that can handle them. You can use set_exception_handler to define such an exception handler that catches all uncaught exceptions by default (this is probably the case in your example from Zend Framework). Plainly put: Only catch exceptions in places where you know how to handle them.
Only use exceptions as what the name implies: to handle (unexpected) exceptions in your control flow. Using exceptions to control the regular flow of your program is possible, but generally considered bad design (just as a side note, your code samples look alright).
For the sake of completeness, some alternatives to using exceptions:
Use return codes instead of exceptions. This is old-school C-style. The advantage is that you don't need to wrap statements with try/catch-statements. However, you have to check the return values of each procedure, which is easy to forget. When using exceptions on the other hand, you reduce the risk of unexpected errors, since uncaught exceptions produce a fatal error per default.
Use PHP errors. See the trigger_error function for this. Custom errors are however nearly impossible to catch in PHP (except by using set_error_handler, which only works at global level).

Handling errors in a class, what method should I use?

I have been dealing with PHP since 2000, but not very actively, and my knowledge of PHP5 is quite horrible. Recently I got my interest for webdevelopment back after a 5 year long break, and I started working on a project. I wrote a class for that project that became fairly large, but so far without any specific error handling.
The purpose of the class is to parse HTML files with a specific layout and handle its data, and it was more or less a training exercise for me to get back into the game. I started to rewrite the class now, and I decided it was time to be a little more professional about error handling than simply using die(), which I have been using a lot so far. I think we can all agree that is a terrible direction to take. I want the class to be quite project independent, so that I can distribute it to whoever wants to use it.
The HTML files I want to parse contain tables with specific bordercolors, trs with specific bgcolors, but the number of elements are dynamic. To validate that the HTML files actually have this specific pattern, I have the following sample (pseudo)code
public function Validate() {
$tables = getall('table', $this->data);
foreach ($tables as $table) {
if ($table->bordercolor != 'navy' && $table->cellspacing != 0) {
// Error
}
foreach ($tables->tr as $tr) {
if ($tr->bgcolor != '#fff') {
// Error
}
}
}
return true;
}
Where it says // Error, the HTML layout doesn't check out and my class should not attempt to parse it. Traditionally I would do this:
if ($table->bgcolor != '#fff') {
$this->error = 'Invalid HTML layout';
return false;
}
And from where I call the method I would use
if ($class->Validate() === false) {
exit_with_error($class->GetError()); // Simple return of $this->error
}
I've always thought it's a decent approach because of it's simplicity. However that's also a disadvantage as it doesn't really provide any in-depth information of the error apart from the text itself. I can't see where the error was triggered, what methods were called, etc.
Since I resumed my PHP hobby I have discovered exceptions. My problem with them is simply that I don't understand how to properly use them. And if I should use them at all. I would like my class to be portable; can I use exceptions to handle errors at all? And if yes, how can I communicate the errors (i.e. translate my traditional error handling)? Or perhaps there is an even better approach to take, which I don't know about.
Any help appreciated :)
You are certainly thinking along the right path. Typically, I like to separatte class design from error handling logic. In other words I don't want to have a bunch of $this->error = 'something' logic in the class, as why would you want to add extra code to every class to store/handle/report errors.
Now you get into exceptions vs. errors and when to use each. This is likely a subject for debate, but my personal preference has largely been to throw Exceptions in cases where you get to a point in your code that you cannot recover from or do not have the logic to handle. A great example of this, that I typically use, is throwing Exceptions right at the beginning of any class method that requires parameters of a certain sort or value. Like this example:
public method set_attribute($value) {
if (empty($value)) {
throw new Exception('You must send me something');
} else if (!is_string($value)) {
throw new Exception("You sent me something but it wasn't the string I was expecting.");
}
// method logic here
}
Here if the caller didn't give us a non-empty string, we throw an Exception, as we were not expecting this and we can't guarantee successful completion of the method without a proper value. There is not reason to continue with the method at all. We send the caller the exception with a message about the problem. Hopefully they invoked this method in a try-catch block and can gracefully handle the exception and pass it along up the call stack. If not, your code just stopped execution with fatal error from an uncaught exception (something really easy to catch in testing).
Triggering errors, I honestly use a lot less, and typically use them more for debug, warning purposes. An example of this might be a deprecated method that you still want to work, but you want to give the user an error on
public function old_method() {
trigger_error('This method had been deprecated. You should consider not using it anymore.'. E_USER_WARNING);
// method logic
}
Of course you can trigger whatever level of E_USER class warning here yourself.
Like I said, I tend to work a lot more with Exceptions, as they are also easily extensible for easy use with logging and such. I almost always would have a custom Exception class extending from PHP's base Exception class that also provides logging, etc.
The other thing to consider is global error handling and Exceptoin handling. I strongly recommend using these and having these be some of the very first lines of code in any new project. Again, it will give you much better control over how you log errors/exceptions than what you can get by default.
I don't see a problem with how you are doing it, but If you want to dive into Exceptions, learn how to use try/catch statements. Usually it would be something like this:
try {
//some code that may cause an error here
} catch (Exception e) {
//if a error is found, or an exception is thrown in the try statement, whatever here will execute
//you can get the error message by using e->getMessage()
}
you can read more about it here: http://php.net/manual/en/language.exceptions.php

set_error_handler vs set_exception_handler [duplicate]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
What are the pros/cons of doing either way. Is there One Right Way(tm) ?
If you want to use exceptions instead of errors for your entire application, you can do it with ErrorException and a custom error handler (see the ErrorException page for a sample error handler). The only downside to this method is that non-fatal errors will still throw exceptions, which are always fatal unless caught. Basically, even an E_NOTICE will halt your entire application if your error_reporting settings do not suppress them.
In my opinion, there are several benefits to using ErrorException:
A custom exception handler will let you display nice messages, even for errors, using set_exception_handler.
It does not disrupt existing code in any way... trigger_error and other error functions will still work normally.
It makes it really hard to ignore stupid coding mistakes that trigger E_NOTICEs and E_WARNINGs.
You can use try/catch to wrap code that may generate a PHP error (not just exceptions), which is a nice way to avoid using the # error suppression hack:
try {
$foo = $_GET['foo'];
} catch (ErrorException $e) {
$foo = NULL;
}
You can wrap your entire script in a single try/catch block if you want to display a friendly message to your users when any uncaught error happens. (Do this carefully, because only uncaught errors and exceptions are logged.)
You should use exceptions in "Exceptional circumstances", that is when you call a method doFoo() you should expect it to perform, if for some reason doFoo is unable to do it's job then it should raise an exception.
A lot of old php code would take the approach of returning false or null when a failure has occured, but this makes things hard to debug, exceptions make this debugging much easier.
For example say you had a method called getDogFood() which returned an array of DogFood objects, if you called this method and it returns null when something goes wrong how will your calling code be able to tell whether null was returned because there was an error or there is just no dog food available?
Regarding dealing with legacy code libraries that use php's inbuilt error logging, you can override the error logging with the set_error_handler() function, which you could use to then rethrow a generic Exception.
Now that you have all of your code throwing detailed exceptions, you are free to decide what to do with them, in some parts of your code you may wish to catch them and try alternative methods or you can log them using your own logging functions which might log to a database, file, email - whichever you prefer. In short - Exceptions are more flexible .
I love the idea of using exceptions, but I often have third party libraries involved, and then if they don't use exceptions you end up with 3-4 different approaches to the problem! Zend uses exceptions. CakePHP uses a custom error handler, and most PEAR libraries use the PEAR::Error object.
I which there WAS one true way in this regard. The custom error handlers route is probably the most flexible in this situation. Exceptions are a great idea though if you're either only using your own code, or using libraries that use them.
Unfortunately in the PHP world we're still suffering from the refusal to die of PHP4, so things like exceptions, while they may represent best practise have been incredibly slow to catch on while everyone is still writing things to be able to work in both 4 and 5. Hopefully this debacle is now ending, though by the time it does, we'll have tensions between 6 and 5 instead...
/me holds head in hands...
It depends on the situation. I tend to use Exceptions when I am writing business logic/application internals, and trigger_error for Validator's and things of that sort.
The pro's of using Exceptions at the logic level is to allow your application to do in case of such an error. You allow the application to chose instead of having the business logic know how to present the error.
The pro's of using trigger_error for Validator's and things of that nature are, say,
try {
$user->login();
} catch (AuthenticationFailureException $e) {
set_error_handler("my_login_form_handler");
trigger_error("User could not be logged in. Please check username and password and try again!");
} catch (PersistenceException $pe) { // database unavailable
set_error_handler("my_login_form_handler");
trigger_error("Internal system error. Please contact the administrator.");
}
where my_login_form_handler pretties up the string and places the element in a visible area above the login form.
The idea of exception is elegant and makes the error handling process so smooth. but this only applies when you have appropriate exception classes and in team development, one more important thing is "standard" exceptions. so if you plan to use exceptions, you'd better first standardize your exception types, or the better choice is to use exceptions from some popular framework. one other thing that applies to PHP (where you can write your code object orienter combined with structural code), is that if you are writing your whole application using classes. If you are writing object oriented, then exceptions are better for sure. after all I think your error handling process will be much smoother with exception than trigger_error and stuff.
Obviously, there's no "One Right Way", but there's a multitude of opinions on this one. ;)
Personally i use trigger_error for things the exceptions cannot do, namely notices and warnings (i.e. stuff you want to get logged, but not stop the flow of the application in the same way that errors/exceptions do (even if you catch them at some level)).
I also mostly use exceptions for conditions that are assumed to be non-recoverable (to the caller of the method in which the exception occurs), i.e. serious errors. I don't use exceptions as an alternative to returning a value with the same meaning, if that's possible in a non-convoluted way. For example, if I create a lookup method, I usually return a null value if it didn't find whatever it was looking for instead of throwing an EntityNotFoundException (or equivalent).
So my rule of thumb is this:
As long as not finding something is a reasonable result, I find it much easier returning and checking for null-values (or some other default value) than handling it using a try-catch-clause.
If, on the other hand, not finding it is a serious error that's not within the scope of the caller to recover from, I'd still throw an exception.
The reason for throwing exceptions in the latter case (as opposed to triggering errors), is that exceptions are much more expressive, given that you use properly named Exception subclasses. I find that using PHP's Standard Library's exceptions is a good starting point when deciding what exceptions to use: http://www.php.net/~helly/php/ext/spl/classException.html
You might want to extend them to get more semantically correct exceptions for your particular case, however.
Intro
In my personal experience, as a general rule, I prefer to use Exceptions in my code instead of trigger_error. This is mainly because using Exceptions is more flexible than triggering errors. And, IMHO, this is also beneficial not only for myself as for the 3rd party developer.
I can extend the Exception class (or use exception codes) to explicitly differentiate the states of my library. This helps me and 3rd party developers in handling and debugging the code. This also exposes where and why it can fail without the need for source code browsing.
I can effectively halt the execution of my Library without halting the execution of the script.
The 3rd party developer can chain my Exceptions (in PHP > 5.3.*) Very useful for debugging and might be handy in handling situations where my library can fail due to disparate reasons.
And I can do all this without imposing how he should handle my library failures. (ie: creating complex error handling functions). He can use a try catch block or just use an generic exception handler
Note:
Some of these points, in essence, are also valid for trigger_error, just a bit more complex to implement. Try catch blocks are really easy to use and very code friendly.
Example
I think this is an example might illustrate my point of view:
class HTMLParser {
protected $doc;
protected $source = null;
public $parsedHtml;
protected $parseErrors = array();
public function __construct($doc) {
if (!$doc instanceof DOMDocument) {
// My Object is unusable without a valid DOMDOcument object
// so I throw a CriticalException
throw new CriticalException("Could not create Object Foo. You must pass a valid DOMDOcument object as parameter in the constructor");
}
$this->doc = $doc;
}
public function setSource($source) {
if (!is_string($source)) {
// I expect $source to be a string but was passed something else so I throw an exception
throw new InvalidArgumentException("I expected a string but got " . gettype($source) . " instead");
}
$this->source = trim($source);
return $this;
}
public function parse() {
if (is_null($this->source) || $this->source == '') {
throw new EmptyStringException("Source is empty");
}
libxml_use_internal_errors(true);
$this->doc->loadHTML($this->source);
$this->parsedHtml = $this->doc->saveHTML();
$errors = libxml_get_errors();
if (count($errors) > 0) {
$this->parseErrors = $errors;
throw new HtmlParsingException($errors[0]->message,$errors[0]->code,null,
$errors[0]->level,$errors[0]->column,$errors[0]->file,$errors[0]->line);
}
return $this;
}
public function getParseErrors() {
return $this->parseErrors;
}
public function getDOMObj() {
return clone $this->doc;
}
}
Explanation
In the constructor I throw a CriticalException if the param passed is not of type DOMDocument because without it my library will not work at all.
(Note: I could simply write __construct(DOMDocument $doc) but this is just an example).
In setsource() method I throw a InvalidArgumentException if the param passed is something other than a string. I prefer to halt the library execution here because source property is an essential property of my class and an invalid value will propagate the error throughout my library.
The parse() method is usually the last method invoked in the cycle. Even though I throw a XmlParsingException if libXML finds a malformed document, the parsing is completed first and the results usable (to an extent).
Handling the example library
Here's an example how to handle this made up library:
$source = file_get_contents('http://www.somehost.com/some_page.html');
try {
$parser = new HTMLParser(new DOMDocument());
$parser->setSource($source)
->parse();
} catch (CriticalException $e) {
// Library failed miserably, no recover is possible for it.
// In this case, it's prorably my fault because I didn't pass
// a DOMDocument object.
print 'Sorry. I made a mistake. Please send me feedback!';
} catch (InvalidArgumentException $e) {
// the source passed is not a string, again probably my fault.
// But I have a working parser object.
// Maybe I can try again by typecasting the argument to string
var_dump($parser);
} catch (EmptyStringException $e) {
// The source string was empty. Maybe there was an error
// retrieving the HTML? Maybe the remote server is down?
// Maybe the website does not exist anymore? In this case,
// it isn't my fault it failed. Maybe I can use a cached
// version?
var_dump($parser);
} catch (HtmlParsingException $e) {
// The html suplied is malformed. I got it from the interwebs
// so it's not my fault. I can use $e or getParseErrors()
// to see if the html (and DOM Object) is usable
// I also have a full functioning HTMLParser Object and can
// retrieve a "loaded" functioning DOMDocument Object
var_dump($parser->getParseErrors());
var_dump($parser->getDOMObj());
}
$var = 'this will print wether an exception was previously thrown or not';
print $var;
You can take this further and nest try catch blocks, chain exceptions, run selective code following a determined exception chain path, selective logging, etc...
As a side note, using Exceptions does not mean that the PROGRAM execution will halt, it just means that the code depending of my object will be bypassed. It's up to me or the 3rd party developer to do with it as he pleases.
The Exceptions are the modern and robust way of signaling an error condition / an exceptional situation. Use them :)
Using exceptions are not a good idea in the era of 3rd party application integration.
Because, the moment you try to integrate your app with something else, or someone else's app with yours, your entire application will come to a halt the moment a class in some 3rd party plugin throws an exception. Even if you have full fledged error handling, logging implemented in your own app, someone's random object in a 3rd party plugin will throw an exception, and your entire application will stop right there.
EVEN if you have the means in your application to make up for the error of that library you are using....
A case in example may be a 3rd party social login library which throws an exception because the social login provider returned an error, and kills your entire app unnecessarily - hybridauth, by the way. So, There you have an entire app, and there you have a library bringing in added functionality for you - in this case, social login - and even though you have a lot of fallback stuff in the case a provider does not authenticate (your own login system, plus like 20 or so other social login providers), your ENTIRE application will come to a grinding halt. And you will end up having to change the 3rd party library to work around these issues, and the point of using a 3rd party library to speed up development will be lost.
This is a serious design flaw in regard to philosophy of handling errors in PHP. Lets face it - under the other end of most of applications developed today, there is a user. Be it an intranet user, be it a user over internet, be it a sysadmin, it does not matter - there is generally a user.
And, having an application die on your face without there being anything you can do at that point other than to go back to a previous page and have a shot in the dark regarding what you are trying to do, as a user, is bad, bad practice from development side. Not to mention, an internal error which only the developers should know due to many reasons (from usability to security) being thrown on the face of a user.
As a result, im going to have to just let go of a particular 3rd party library (hybridauth in this case) and not use it in my application, solely for that reason. Despite the fact that hybridauth is a very good library, and apparently a lot of good effort have been spent on it, with a phletora of capabilities.
Therefore, you should refrain from using exceptions in your code. EVEN if the code you are doing right now, is the top level code that will run your application, and not a library, it is possible that you may want to include all or part of your code in other projects, or have to integrate parts or entirety of it with other code of yours or 3rd party code. And if you used exceptions, you will end up with the same situation - entire applications/integrations dying in your face even if you have proper means to handle whatever issue a piece of code provides.

dealing with complex results in objects -- exceptions?

What is the general way of handling complex results from functions with an object? A simple method might return true or false, and that would be all I need to know. A more complex method might return true or false, but there might be more information I would want to get out of the class, such as why it failed ( there might be several reasons ).
I could do it with an exception, but I've read in some places that using an exception for a "normal" functions isn't good practice. Also since throwing an exception destroys the object, I can't do anything else with it, so an exception wouldn't work if I want to continue to use the object. It seems to me that an exception should be thrown when things are really wrong, not an expected, recoverable error.
So, another way to this is to have a result property after having run a method, and if that method returns false, I can ask what the result state for it is. Is this the way to do it?
Obvious solution: Return an array, like ("success" => false, "explanation" => "saw a mouse and ran screaming like a little girl", "solution" => "call an exterminator").
I'd suggest you to always keep the methods signatures' predictable, i.e. always return the same type (be it an array, boolean, anything else.)
I think the example of validating with Zend_Validate uses a sensible solution to your problem by differentiating the result from the eventual errors.
Exceptions do not destroy the object, but if you catch an exception in a place where you have no reference to the object, then you can loose the object - it is still there until garbage collection.
If you create your own exception class you could even add the object in question as a member to the exception, so the object is available where you handle the exception.
The exception to this rule is when you throw an exception in an object constructor. Then the object in question is never created in the first place.
The use of Exceptions vs other error mechanisms is as old as Exceptions are. Exceptions are a method for handling errors and in many circumstances they work very well and result in cleaner code than when not using them.
Whether they are a good solution for a specific problem is partly a matter of experience, so you will have to try them out to learn to use them.

In PHP5, should I use Exceptions or trigger_error/set_error_handler? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
What are the pros/cons of doing either way. Is there One Right Way(tm) ?
If you want to use exceptions instead of errors for your entire application, you can do it with ErrorException and a custom error handler (see the ErrorException page for a sample error handler). The only downside to this method is that non-fatal errors will still throw exceptions, which are always fatal unless caught. Basically, even an E_NOTICE will halt your entire application if your error_reporting settings do not suppress them.
In my opinion, there are several benefits to using ErrorException:
A custom exception handler will let you display nice messages, even for errors, using set_exception_handler.
It does not disrupt existing code in any way... trigger_error and other error functions will still work normally.
It makes it really hard to ignore stupid coding mistakes that trigger E_NOTICEs and E_WARNINGs.
You can use try/catch to wrap code that may generate a PHP error (not just exceptions), which is a nice way to avoid using the # error suppression hack:
try {
$foo = $_GET['foo'];
} catch (ErrorException $e) {
$foo = NULL;
}
You can wrap your entire script in a single try/catch block if you want to display a friendly message to your users when any uncaught error happens. (Do this carefully, because only uncaught errors and exceptions are logged.)
You should use exceptions in "Exceptional circumstances", that is when you call a method doFoo() you should expect it to perform, if for some reason doFoo is unable to do it's job then it should raise an exception.
A lot of old php code would take the approach of returning false or null when a failure has occured, but this makes things hard to debug, exceptions make this debugging much easier.
For example say you had a method called getDogFood() which returned an array of DogFood objects, if you called this method and it returns null when something goes wrong how will your calling code be able to tell whether null was returned because there was an error or there is just no dog food available?
Regarding dealing with legacy code libraries that use php's inbuilt error logging, you can override the error logging with the set_error_handler() function, which you could use to then rethrow a generic Exception.
Now that you have all of your code throwing detailed exceptions, you are free to decide what to do with them, in some parts of your code you may wish to catch them and try alternative methods or you can log them using your own logging functions which might log to a database, file, email - whichever you prefer. In short - Exceptions are more flexible .
I love the idea of using exceptions, but I often have third party libraries involved, and then if they don't use exceptions you end up with 3-4 different approaches to the problem! Zend uses exceptions. CakePHP uses a custom error handler, and most PEAR libraries use the PEAR::Error object.
I which there WAS one true way in this regard. The custom error handlers route is probably the most flexible in this situation. Exceptions are a great idea though if you're either only using your own code, or using libraries that use them.
Unfortunately in the PHP world we're still suffering from the refusal to die of PHP4, so things like exceptions, while they may represent best practise have been incredibly slow to catch on while everyone is still writing things to be able to work in both 4 and 5. Hopefully this debacle is now ending, though by the time it does, we'll have tensions between 6 and 5 instead...
/me holds head in hands...
It depends on the situation. I tend to use Exceptions when I am writing business logic/application internals, and trigger_error for Validator's and things of that sort.
The pro's of using Exceptions at the logic level is to allow your application to do in case of such an error. You allow the application to chose instead of having the business logic know how to present the error.
The pro's of using trigger_error for Validator's and things of that nature are, say,
try {
$user->login();
} catch (AuthenticationFailureException $e) {
set_error_handler("my_login_form_handler");
trigger_error("User could not be logged in. Please check username and password and try again!");
} catch (PersistenceException $pe) { // database unavailable
set_error_handler("my_login_form_handler");
trigger_error("Internal system error. Please contact the administrator.");
}
where my_login_form_handler pretties up the string and places the element in a visible area above the login form.
The idea of exception is elegant and makes the error handling process so smooth. but this only applies when you have appropriate exception classes and in team development, one more important thing is "standard" exceptions. so if you plan to use exceptions, you'd better first standardize your exception types, or the better choice is to use exceptions from some popular framework. one other thing that applies to PHP (where you can write your code object orienter combined with structural code), is that if you are writing your whole application using classes. If you are writing object oriented, then exceptions are better for sure. after all I think your error handling process will be much smoother with exception than trigger_error and stuff.
Obviously, there's no "One Right Way", but there's a multitude of opinions on this one. ;)
Personally i use trigger_error for things the exceptions cannot do, namely notices and warnings (i.e. stuff you want to get logged, but not stop the flow of the application in the same way that errors/exceptions do (even if you catch them at some level)).
I also mostly use exceptions for conditions that are assumed to be non-recoverable (to the caller of the method in which the exception occurs), i.e. serious errors. I don't use exceptions as an alternative to returning a value with the same meaning, if that's possible in a non-convoluted way. For example, if I create a lookup method, I usually return a null value if it didn't find whatever it was looking for instead of throwing an EntityNotFoundException (or equivalent).
So my rule of thumb is this:
As long as not finding something is a reasonable result, I find it much easier returning and checking for null-values (or some other default value) than handling it using a try-catch-clause.
If, on the other hand, not finding it is a serious error that's not within the scope of the caller to recover from, I'd still throw an exception.
The reason for throwing exceptions in the latter case (as opposed to triggering errors), is that exceptions are much more expressive, given that you use properly named Exception subclasses. I find that using PHP's Standard Library's exceptions is a good starting point when deciding what exceptions to use: http://www.php.net/~helly/php/ext/spl/classException.html
You might want to extend them to get more semantically correct exceptions for your particular case, however.
Intro
In my personal experience, as a general rule, I prefer to use Exceptions in my code instead of trigger_error. This is mainly because using Exceptions is more flexible than triggering errors. And, IMHO, this is also beneficial not only for myself as for the 3rd party developer.
I can extend the Exception class (or use exception codes) to explicitly differentiate the states of my library. This helps me and 3rd party developers in handling and debugging the code. This also exposes where and why it can fail without the need for source code browsing.
I can effectively halt the execution of my Library without halting the execution of the script.
The 3rd party developer can chain my Exceptions (in PHP > 5.3.*) Very useful for debugging and might be handy in handling situations where my library can fail due to disparate reasons.
And I can do all this without imposing how he should handle my library failures. (ie: creating complex error handling functions). He can use a try catch block or just use an generic exception handler
Note:
Some of these points, in essence, are also valid for trigger_error, just a bit more complex to implement. Try catch blocks are really easy to use and very code friendly.
Example
I think this is an example might illustrate my point of view:
class HTMLParser {
protected $doc;
protected $source = null;
public $parsedHtml;
protected $parseErrors = array();
public function __construct($doc) {
if (!$doc instanceof DOMDocument) {
// My Object is unusable without a valid DOMDOcument object
// so I throw a CriticalException
throw new CriticalException("Could not create Object Foo. You must pass a valid DOMDOcument object as parameter in the constructor");
}
$this->doc = $doc;
}
public function setSource($source) {
if (!is_string($source)) {
// I expect $source to be a string but was passed something else so I throw an exception
throw new InvalidArgumentException("I expected a string but got " . gettype($source) . " instead");
}
$this->source = trim($source);
return $this;
}
public function parse() {
if (is_null($this->source) || $this->source == '') {
throw new EmptyStringException("Source is empty");
}
libxml_use_internal_errors(true);
$this->doc->loadHTML($this->source);
$this->parsedHtml = $this->doc->saveHTML();
$errors = libxml_get_errors();
if (count($errors) > 0) {
$this->parseErrors = $errors;
throw new HtmlParsingException($errors[0]->message,$errors[0]->code,null,
$errors[0]->level,$errors[0]->column,$errors[0]->file,$errors[0]->line);
}
return $this;
}
public function getParseErrors() {
return $this->parseErrors;
}
public function getDOMObj() {
return clone $this->doc;
}
}
Explanation
In the constructor I throw a CriticalException if the param passed is not of type DOMDocument because without it my library will not work at all.
(Note: I could simply write __construct(DOMDocument $doc) but this is just an example).
In setsource() method I throw a InvalidArgumentException if the param passed is something other than a string. I prefer to halt the library execution here because source property is an essential property of my class and an invalid value will propagate the error throughout my library.
The parse() method is usually the last method invoked in the cycle. Even though I throw a XmlParsingException if libXML finds a malformed document, the parsing is completed first and the results usable (to an extent).
Handling the example library
Here's an example how to handle this made up library:
$source = file_get_contents('http://www.somehost.com/some_page.html');
try {
$parser = new HTMLParser(new DOMDocument());
$parser->setSource($source)
->parse();
} catch (CriticalException $e) {
// Library failed miserably, no recover is possible for it.
// In this case, it's prorably my fault because I didn't pass
// a DOMDocument object.
print 'Sorry. I made a mistake. Please send me feedback!';
} catch (InvalidArgumentException $e) {
// the source passed is not a string, again probably my fault.
// But I have a working parser object.
// Maybe I can try again by typecasting the argument to string
var_dump($parser);
} catch (EmptyStringException $e) {
// The source string was empty. Maybe there was an error
// retrieving the HTML? Maybe the remote server is down?
// Maybe the website does not exist anymore? In this case,
// it isn't my fault it failed. Maybe I can use a cached
// version?
var_dump($parser);
} catch (HtmlParsingException $e) {
// The html suplied is malformed. I got it from the interwebs
// so it's not my fault. I can use $e or getParseErrors()
// to see if the html (and DOM Object) is usable
// I also have a full functioning HTMLParser Object and can
// retrieve a "loaded" functioning DOMDocument Object
var_dump($parser->getParseErrors());
var_dump($parser->getDOMObj());
}
$var = 'this will print wether an exception was previously thrown or not';
print $var;
You can take this further and nest try catch blocks, chain exceptions, run selective code following a determined exception chain path, selective logging, etc...
As a side note, using Exceptions does not mean that the PROGRAM execution will halt, it just means that the code depending of my object will be bypassed. It's up to me or the 3rd party developer to do with it as he pleases.
The Exceptions are the modern and robust way of signaling an error condition / an exceptional situation. Use them :)
Using exceptions are not a good idea in the era of 3rd party application integration.
Because, the moment you try to integrate your app with something else, or someone else's app with yours, your entire application will come to a halt the moment a class in some 3rd party plugin throws an exception. Even if you have full fledged error handling, logging implemented in your own app, someone's random object in a 3rd party plugin will throw an exception, and your entire application will stop right there.
EVEN if you have the means in your application to make up for the error of that library you are using....
A case in example may be a 3rd party social login library which throws an exception because the social login provider returned an error, and kills your entire app unnecessarily - hybridauth, by the way. So, There you have an entire app, and there you have a library bringing in added functionality for you - in this case, social login - and even though you have a lot of fallback stuff in the case a provider does not authenticate (your own login system, plus like 20 or so other social login providers), your ENTIRE application will come to a grinding halt. And you will end up having to change the 3rd party library to work around these issues, and the point of using a 3rd party library to speed up development will be lost.
This is a serious design flaw in regard to philosophy of handling errors in PHP. Lets face it - under the other end of most of applications developed today, there is a user. Be it an intranet user, be it a user over internet, be it a sysadmin, it does not matter - there is generally a user.
And, having an application die on your face without there being anything you can do at that point other than to go back to a previous page and have a shot in the dark regarding what you are trying to do, as a user, is bad, bad practice from development side. Not to mention, an internal error which only the developers should know due to many reasons (from usability to security) being thrown on the face of a user.
As a result, im going to have to just let go of a particular 3rd party library (hybridauth in this case) and not use it in my application, solely for that reason. Despite the fact that hybridauth is a very good library, and apparently a lot of good effort have been spent on it, with a phletora of capabilities.
Therefore, you should refrain from using exceptions in your code. EVEN if the code you are doing right now, is the top level code that will run your application, and not a library, it is possible that you may want to include all or part of your code in other projects, or have to integrate parts or entirety of it with other code of yours or 3rd party code. And if you used exceptions, you will end up with the same situation - entire applications/integrations dying in your face even if you have proper means to handle whatever issue a piece of code provides.

Categories