I'm working on the back-end of my website and I'm wondering how far I should be going to test for errors and throwing exceptions accordingly? Testing in the sense of improper usage of methods and functions. Not errors under correct usage.
My biggest concern is code bloat and uglying it up with a bunch of if/elses, type checks, and other such tests.
Should you go so far as to consider every possible way someone could use an object, catch all the improper uses, and throw exceptions to make it clear to the developer using it what they've done wrong?
Or is it a better approach to let the code break naturally (obviously catching and checking for things that would be a big deal, but not for every contingency), and depend on anyone using the code to read the available documentation and use it accordingly?
Are there any general best practices or guidelines to follow when handling such issues? I'm working in PHP, is there anything specific to PHP, although this issue is generally language wide?
Thanks for any help on the matter.
At least, your application should not "break" : when an error is detected (be it because you detected a problem could happen and avoided it, or because a problem did happen), you should display some nice error message, and, eventually, log the technical informations of the error.
About bloating the code : I would not put too much tests and all that in my code : it would end up in something hard to understand and maintain -- which is important !
What I generally try to do is :
Test for errors in the user-supplied data
Using a specific class, for instance, so those checks are not in the middle of the code that deals with database and business rules.
Those tests are relatively precise, in order to generate useful error messages for the user
For instance : "You should not input more than 20 characters"
Or "there is already a user with that e-mail address"
Basically, the important thing here is the user.
When user-supplied data seems OK, I work with it.
And there, if some error happens, it'll most likely be a technical error
Which should be logged
And only a "oops, an error occured" should be displayed to the user.
Which means that, here, tests are not as precise : we only need to know if it works or not -- not necessarily in great details.
Of course, in the end, you should ensure that the data in the DB is correct, and that you don't save only half of the data.
A common way of dealing with technical errors is using exceptions ; here is a very basic idea :
try {
// Begin transaction to the DB
// Some code that might fail and throw an Exception
// Some other code that might fail and throw an Exception
// Code here will not be executed if an Exception has been thrown
// Commit DB transaction
} catch (Exception $e) {
// Rollback transaction (cancels the queries that were sent to the DB)
// Log technical informations to a file
// Display a nice message
}
The great thing is that it allows one to place all error-handling code in a single place, and put less testing code in the middle of the important stuff ; i.e. "let it fail, we'll deal with the problems later"
I usually just go as far as making sure method input parameters and/or public members are filled and of the proper type (string, int, etc...). Other than that I just let it break naturally. (If people aren't going to bother reading the documentation, they kind of deserve to have things break a little.)
As I see it, you don't bloat your code with error-checks, who's only purpose would be to support the laziness of your co-workers/clients/random-developers.
Related
When do you want to check to see if a query completed successfully? Often in code I see a mixed bag of either checking if a update/insert/delete statement completed successfully (e.g. if ($query) { echo 'success' } or no checking at all.
I googled to see what the recommended choice was, but didn't find any relevant results. Further, I also realize this question is quite subjective depending on how sensitive the data is. But at the same time, unless the coder made a seriously malformed query to begin with, what is the point of checking if a query completed?
if ($user->update_user($this->input->input_stream(), $info) === false) {
encode_response('error', $this->n_config->get('query_error'));
} else {
encode_response('success', Auth_lang::get('user_updated_successfully'));
}
Always. Always. Always check for errors. You cannot presume that one query has succeeded and then blindly stumble on to the next step or bad things will eventually happen.
The easiest way to check for errors is to have everything automatically checked: Enable exceptions. These will be fired if there's a problem, you won't have to manually check on each call. You will, however, have to figure out how and where to catch these so they don't blow up your whole application.
Programmers come from different backgrounds and have differing opinions on how to do these things, and some are just too lazy to bother doing them at all. In C code there's no such thing as exceptions, so those sorts of developers are used to testing for error codes. In Java exceptions are such an embedded part of the ecosystem they're a given and people use them judiciously.
PHP isn't sure what kind of a programming language it is, you can use exceptions if you want to and error codes if that's more your style. This is why you see an unusually high level of diversity in approaches to these things.
So basically today I decided to test out using some exceptions in a simple login method because I have been reading about them for a while on loads of sites but when I start adding them into my code they just end up confusing me so today is hopefully the day I will find out what what I am doing wrong.
This is the login method (Just the validating input part, no database stuff or meaningful messages):
public function login($username, $password) {
try {
$this->security->validateInput($username, 'String', array(20, 6), 'username');
}
catch(InvalidArgumentException $e) {
echo $e->getMessage();
}
catch(LengthException $e) {
echo $e->getMessage();
}
catch(InvalidFormatException $e) {
echo $e->getMessage();
}
}
You can see from the catch blocks what exceptions the validateInput() method throws.
What I don't get is I have the $password variable to validate too but it just does not make sense to me to put it under the validation of the $username like:
try {
$this->security->validateInput($username, 'String', array(20, 6), 'username');
$this->security->validateInput($password, 'String', array(16, 8), 'password');
}
Am I using exceptions the complete wrong way and maybe they are not supposed to be used in login scripts and other similar scripts?
Any help would be great thanks.
Define "need"
Whether or not you "need" to throw an exception in a particular case is probably something that is up for debate. Especially with loosely typed languages like PHP. If your interested on some of the arguments on when to use exceptions, you can mosey on over to Programmers.SE and see what they have to say on the topic. Specifically, you can take a look at the question Defensive Programming Vs Exception Handling. For the rest of my answer, I'm going to ignore whether or not you "need" to throw an exception, or even if it is the right thing to do. I'm going to do my best to leave correctness arguments aside and focus on your problem.
Stumbling Through the Dark
So let's examine the problem. You are trying to login a user via a PHP script using OOP. First off, I'm sorry about that. OOP in PHP is terrible in my opinion. But, how to handle validation is something that really comes with a lot of personal preference, as well as situation. So, let's answer some questions first:
How are other scripts interacting with this?
An important thing to consider with validation is how other scripts are going to be interacting with this. If you are coding a simple login form for a website, and your validation only needs to occur on your login page, it can be easier to not worry about exceptions, but to simply show or redirect the user to a page indicating there was an error without logging them in. On the other hand, if you are needing to interact with this from multiple different pages, or sites, or in a manner in which a simple redirect isn't possible, it would probably be easier to throw an error and let the calling code figure out how to handle it.
Do you want to treat all exceptions differently?
For security reasons, you should not handle the username and password with different error messages. This gives an easy way to find out if a username is correct, and is a security issue (most of the time). Also don't say if they were "close". But, does that mean you want to handle invalid characters in a username the same? This is a place where exceptions can be useful, as it gives you the flexibility to distinguish errors, while still letting you process them the same if you want. It let's the calling code make that decision instead of having to do it in your validation.
Are other coders going to be using your code?
This is an important one for me. A descriptive exception and message can tell me what assumptions I did wrong, where as a cryptic return value, or a simple redirect I wasn't expecting can be frustrating. If you are trying to create a library, or code that will be reused elsewhere, you should throw descriptive exceptions. Also, have good documentation :)
How is your server configured to handle PHP exceptions?
If you are doing AJAX requests, or similar REST API requests, it can actually be useful to know how your server handles errors from PHP. Many are configured to just throw a "500 Server Error" for any unhandled exceptions. But some, especially if development settings are used, will show the error encountered and print the message. This can be useful when learning, but is poor practice for live sites. You'll want to make sure you are either handling all the exceptions you know about, or you'll want to give useful error messages that you are expecting on the other end.
What Would I do?
With OOP, I always lean towards throwing exceptions rather than handling things using other methods. Exceptions allow things to be reused more easily since you are not reaching into other pieces of code to modify things. Objects should be independent so that you can use your objects again and again and again without having to rewrite it each time. This can be especially useful with things like login validation, since you will be able to fix any issues in 1 place, and you can continually improve it as you learn more.
I have always the "return status code" method to manage errors. It seems that exceptions are nowdays the best formed way to manage errors.
But are they really the best way ? I have read stuff like exceptions are worst than GoTo
Do you know some good articles/posts/books about exceptions and error management?
If you program object orientated, maybe exceptions are better for you. If you write procedural, return values are the better way. It depends on your coding style etc.
Exceptions are about 10000x slower than returning a status/error code depending on the programming language. This is due to all the stack information being kept track of. That's the bad.
In general, you don't ever have to use exceptions. In fact, at one point, the only thing that existed was return codes.
The nice thing about exceptions is that they won't let a program continue unless they are dealt with correctly. Instead, the program crashes.
So, basically, if you are forgetful about handling status messages or are worried that others may not check return codes from your functions, exceptions stop the program and make you fix it. Although, I have seen a lot of inexperienced programmers catch the exception, not do anything about it, and then continue on. This is basically the same as ignoring the return code from a function.
One other nice thing about exceptions is that they "bubble up" automatically. Instead of having to pass back error codes through a long chain of functions, you could set up your try catch at the very top level and handle any error appropriately (assuming you didn't want anything else to happen in between). For example, if anything goes wrong, display an error page.
Ok, this might be a very noob question, but I find that PHP Documentation on that and several Internet Searches hasn't give me any idea about that.
When should I use try-catch blocks to improve my application?
I read someone saying that we should use try-catch blocks only to prevent fatal errors.
I read someone else saying that we should use it only on unexpected errors (wait what? unexpected? if they are unexpected errors how could I prevent them with try-catch? should I put all my application code inside a try block?).
Others simply say that try-catch blocks should be used everywhere because they can be also extended (extending the Exception class).
Finally someone says that PHP try-catch block are totally useless because they are very bad implemented. (On this I found a nice SO question about performance).
It seems to me that this topic is very strange and confused. Could someone lights me up?
It seems to me that this topic is very strange and confused. Could someone lights me up?
Definitely. I'm not a PHP user, but I might have a little insight after having worked with try/catch in ActionScript, Java, and JavaScript. Bear in mind though, that different languages and platforms encourage different uses for try/catch. That said...
The only times I'd recommend using try/catch is if you're using a native language function that
Can throw an error/exception
Does not give you any tools to detect whether you're about to do something stupid that would cause that error/exception. eg: In ActionScript, closing a loader that is not open will result in an error but the loader doesn't have an isOpen property to check so you're forced to wrap it in try/catch to silence an otherwise totally meaningless error.
The error/exception really is meaningless.
Let's take the examples you list and see how they square with that list.
I read someone saying that we should use try-catch blocks only to prevent fatal errors.
In the case of AS's loader.close() function, this is good advice. That's a fatal error, and all from an otherwise trivial misstep. On the other hand, virtually ALL errors in AS will bring your application to a halt. Would you then wrap them all in try/catch? Absolutely not! A "fatal error" is fatal for a reason. It means something terribly wrong has happened and for the application to continue on in a potentially "undefined" state is foolhardy. It's better to know an error happened and then fix it rather than just let it go.
I read someone else saying that we should use it only on unexpected errors
That's even worse. Those are presicely the errors you DON'T want to silence, because silencing them means that you're never going to find them. Maybe you're not swallowing them, though... maybe you're logging them. But why would you try/catch/log/continue as though nothing happened, allowing the program to run in a potentially dangerous and unexpected condition? Just let the error kick you in the teeth and then fix it. There's little more frustrating than trying to debug something that's wrong in a program that someone else wrote because they wrapped everything in a try/catch block and then neglected to log.
Others simply say that try-catch blocks should be used everywhere because they can be also extended (extending the Exception class).
There's potential merit to this if you're the one doing the throwing, and you're trying to alert yourself to an exceptional situation in your program... but why try/catch your own thrown error? Let it kick you in the teeth, then fix it so that you don't need to throw the error anymore.
Finally someone says that PHP try-catch block are totally useless because they are very bad implemented. (On this i find a nice SO question about performance).
Maybe so. I can't answer this one though.
So... this might be a bit of a religious question, and I'm certain people will disagree with me, but from my particular vantage point those are the lessons I've learned over the years about try/catch.
Different people will tell you different things. But this is what I think, specifically in the case of a web application.
Your whole page should be in a try/catch that displays an error message to the user. The error message shouldn't tell the user what happened in detail because thats a security concern. It should record information about the error into a log file.
The other case is where something could go wrong in the normal operation of affairs. PHP is not very exception happy so this may not happen very much. Basically, if you run into a function that throws an exception when it fails, you can catch the exception and do something else in that case.
In general, your question is like asking how you would use a hammer to improve the qualify of a house. Use exceptions to help you implement particular behaviors. Don't look for places to use exceptions.
I think it's simply a matter of preferences, but from my experiences, I'd encourage you to use them as much as possible.
In application we currently develop at work (using Zend Framework if it matters), we use one single try..catch block to catch all exceptions throughout the application which are shown to user as, for example, error 500s and exception is logged with more information to database. I, personally, love this approach in case of PHP application as exceptions are extendable and you can basically write whatever functionality you need.
I predominantly use Try/Catch around database calls...especially inputs, updates and deletes etc.
I sometimes use it around complex data processing with arrays and loops using dynamic data and arrays where there is a chance something might go wrong, ie: missing array elements or something (I normally check for stuff like that though).
I also use them around operations over which I don't have complete control such as importing data from an external or foreign data source where there could be problems with the data or accessing the source file.
I think what is meant by "Unexpected Errors" is where you can't prevent problems through good programming practices such as checking if a file exists before "including" it, Some problems you CAN anticipate so use good practices to prevent them. Don't just leave them to chance by wrapping them in a try/catch.
Use good programming practices instead as you should do everywhere. Don't use try/catch as a lazy shortcut for everything, everywhere. That's major overkill.
I agree with #scriptocalypse. In fact I only use try/catch blocks in PHP in 2 kind of situations.
If it's possible that some external (not inside my code) issues or DB errors may take place:
Getting data from another source (eg. curl)
Getting data from files
DB-Exceptions
If I work inside another system, like a CMS or similar and I want to override a certain behavior. For example I don't want an Exception being thrown but the exceptions message being returned to the view.
You cant put try catch blocks everywhere.
However during application testing, exceptions generated should alert you to places where you need try catches. This is one reason why you should run thorough testing of you application/code.
If you see a place where you think you need it, i would put one in.
EDIT: ok you CAN put them everywhere, but you need some sense as to where to put them in your code.
I normally put Try and Catch around areas in the code that have external forces acting on it that I have no control over. For example, Opening and reading external files.. you have no control that at some point in the reading of the file, the file becomes corrupted or something else happens that you can not control like the file server dc's or something
I was hoping you guys could help me on this one: how to handle errors and what to return?
What I do, most of time, is make my functions/methods return two possible values. The intended value in case of success and FALSE in case of failure. This way I can use:
if(function()) { ... } else { ... }
I don't like to use exceptions because, generally, they print something and interrupt the functioning flow of the application. Of course, I can make them to return something and show an alert with the error. But it's too much work. And I don't like Pokemon so much to try to catch them all. (Awsum topic, btw)
Another thing I'm concerned about is to code something "error-handling" driven. As we know, users can do almost anything to cause an unexpected situation, and to code expecting these errors is too tiring and frankly, is making me paranoid. XD
I apologize for any english mispelling(I don't write too often).
Thank you for reading this question. :D
PS: I read about defensive programming and the other questions but they don't quite answer my doubt.
Maybe you won't find my answer useful because I'm not a php developer, anyway I will try to give you common hints as error handling debates are common in any programming language.
1) First try to avoid the actual need for error handling. This does mean try to code in a way that error conditions are few as possible. A simple example: it's common sense that trying to clear an empty collection should not raise an error.
2) Distinct what is a supported failure than an unsupported one. A supported failure is an error condition that you actually want to track and handle as part of the program logic. An unsupported failure would be an error condition that's actually a code error. For example: you are trying to lookup an element in a map and it's part of the logic of your program that the specific element should be there. There's no sense to add code to test if the element was there and raise an error if it wasn't: you made the assumption it was there.
After you have understood these two points, I'm pretty sure you'll understand why exceptions are so useful to produce cleaner and more efficient code. The trick is: make your code to raise as few exceptions as possible (again: distinct supported and unsupported error conditions to choose what exceptions are actually needed) and catch them only at the most external scope, where the user of your application interact with it and 1)should be warned, 2)should decide what to do. Programmatically catch an excpetion without user interaction is, most of the times, a bad thing because it makes the dev think that catching exceptions is efficient just like conditionally do something (if-then-else) when an error condition arise when this is not the case. Exceptions won't cause any overhead to your application until they are thrown.
Have you tried working with PHP's error logging tools? http://php.net/manual/en/book.errorfunc.php
You can then use things like error_log() to shoot your custom errors to whatever log file you want.
You should consider using Exceptions. They don't print anything if you don't want to. At least this would be a better separation of your actual code and error handling.
You are right, having a function return a value or return false on error is not the best style (yes I know that this is probably done a lot).
If you want to learn more about good coding practice, I suggest to read Clean Code by Robert Martin.