I understood the concept of Exceptions, but I still can't undestand why I should replace the way I do error handling to the Exception way.
Here's a simple code that serves as an example of how I do things without exception:
validate_form_data($data, &$errors=array())
{
//expects $_POST to be passed as argument ($data)
$errors = array();
if(strlen($data['name']) < 3)
$errors[] = "Your name must contain at least 3 characters.";
if($data['age'] > 200)
$errors[] = "You can't be older than 200."
if(count($errors))
return false;
else
return true;
}
///submit_form.php
$errors = array();
if(validate_form_data($_POST, $errors))
{
// do something like sending data to MySQL and output sucess message.
}
else
{
//loop thru the $errors array and display its values so the user knows what mistakes he made
}
My question is: Will using exceptions make my life easier, if so, how?
Exceptions, as their name suggests, should be thrown in exceptional cases in your application. But, since what you're doing is validating data, havinng to deal with invalid data isn't an exceptional case: it's a condition you're expecting. So, using exceptions in that script won't make your life easier, and it isn't even correct.
The only thing I would change is the way you return the errors:
function validate_form_data($data)
{
$errors = array();
if (strlen($data['name']) < 3) {
$errors[] = "Your name must contain at least 3 characters.";
}
if ($data['age'] > 200) {
$errors[] = "You can't be older than 200.";
}
return $errors;
}
I disagree that exceptions imply unexpected problems. For one thing, your code is specifically checking for the problem so it's definitely expected. From the definition of exception,
anything excluded from or not in conformance with a general rule, principle, class, etc.
they are known cases that must be excluded but accounted for. They are designed for situations that require leaving the normal flow of execution and make it easier to handle the problem non-locally.
If the method that detects the error isn't going to handle it, i.e. decide what course of action to take, it can throw an exception so that the caller can either handle it or let it propagate to their caller, and so on. You can do this by returning an error code, but that forces every caller in the execution stack to check for and return an error code. PHP automatically rethrows exceptions to the caller if a method doesn't catch them.
Since the purpose of the method above is to check user input for validity, it makes more sense to return the result of that check: yes or no. Also, you're probably going to use that result in the code that calls the method so there's no need to let the exception bubble up the stack.
Related
This doesn't necessarily only apply to PHP, but that's my area of concern.
I have been writing a few checking functions recently, that get some argument and then check its validity in various ways. Like, checkXmlString($xml) will check whether the given string contains a well-formed xml document, etc.
The question is, should those functions return a boolean, or throw exceptions and not return anything on success.
So
function checkAbc($arg) { if ($arg is invalid) return false; else return true; }
or rather
function checkAbc($arg) { if ($arg is invalid) throw new Exception(...); }
You could throw a InvalidArgumentException to check if arguments are incorrect but i think for your case if you are writing "checkers" they should return a boolean so you know not to continue operations, for example if the foobar.xml is actually a CSV file you wouldn't want to continue with your operation but you wouldn't want to catch an exeption either
<?php
class Checker {
function validXml($string)
{
if(!(bool)$string) throw new \InvalidArgumentException("Cannot pass empty string as argument", 1);
// Check
// Is valid XML ? Return True : return false
}
}
try {
if(new Checker->validXml($xmlString))
{
// Continue Operation
// return
}
// Notify User of invalidity
// return
} catch (\InvalidArgumentException $e) {
// Log args
//
}
According to almost all books written on subject and not least, according to logic, the name should be the biggest hint of what the function does. In that case, only the first option applies. As Bet Lamed said previously, a function called "check" is not supposed to throw exceptions, just to let you know if the check is ok or not.
If you want exceptions, you might want to rename it to DeserialisationToAbc() or TryParseAbc() or something similar.
The question is, should those functions return a boolean, or throw
exceptions and not return anything on success.
First identify If It is an exceptional situation than use exception .You case does not seems to be exceptional, It is just a condition , so treat it like a condition.If It was like It is correct but fails on certain situation, you may not identify well than you may consider using exception.
Visit these two links and learn more about exception
Exception Best Practices in PHP 5.3
A primer on PHP exceptions
This is of course a bit opinion based, but ask yourself, what do you expect from a function like checkEmail() ? The purpose of the method is to validate something, so you propably expect an answer to this question.
$isValid = checkEmail($arg);
I think most developers expect a bool as return value, it makes the code readable. Wrong values are expected, so one cannot say it is an exception if an invalid argument is passed. To return an error message as well i would use an out parameter:
function checkAbc($arg, &$errorMessage)
{
if ($arg is invalid)
{
$errorMessage = 'The argument is invalid because of...';
return false;
}
else
{
$errorMessage = '';
return true;
}
}
I'm really not quite sure which form is preferrable in general.
On the one hand, in case of an error, you want a useful message, so you end up with mixed returns (true/string), which is ugly, or returning an array (even uglier). An exception gives you that for free.
On the other hand, a function called check...() should not be expected to throw an exception, because finding out that "this is not a valid thingie" is nothing exceptional and not an error.
The third way would be to call it "throwIfFalse", but that's ugly too....
Hmm....
One possible solution:
interface Checker {
public function check();
public function getMessage();
}
class WhateverChecker implements Checker { ... }
class ClientOfChecker {
public function doStuff() {
$checker = new Checker();
if (! $checker->check() )
throw new Exception($checker->getMessage());
}
}
However, that seems incredibly verbose, and, may I say, Javaesque to me.
There is generally 2 types of function regarding your question:
Pure function that tests whether a condition holds.
Function that ensures a condition holds and alters control flow if it does not.
Different programming language may have different conventions about the naming of both types. Take C++ as an example, one common naming is CHECK_XXX for type 2 and IsXXX for type 1.
Here is an example taken from a tutorial of the google-log library:
CHECK(fp->Write(x) == 4) << "Write failed!";
CHECK_NE(1, 2) << ": The world must be ending!";
Another example is the maktaba utility library for Vimscript , where maktaba#value#IsXXX() is used to test whether the argument is of a certain type while maktaba#ensure#IsXXX() is used to ensure IsXXX holds and throws an exception otherwise.
function! TakeAString(name)
" Ensure argument type is String.
let name = maktaba#ensure#IsString(a:name)
endfunction
if maktaba#value#IsString(name)
" Branch if name is a String.
echo name
endif
So here is the point: choose the one that suits your need best and name the function according to the convention of the language. In terms of use cases of both, roughly, use the type 2 to check pre-condition like argument type and use the type 1 in conditional statements.
I have some methods in a class that I think could be useful for testing stuff, but also in some cases the program may want to halt completely if the check fails. Originally I was wrapping the method calls in if conditions and then throwing an exception, however, I ended up having the same if conditions in many methods and it seemed wasteful, so I added a boolean flag to the check method to have it throw an exception if the check failed. An example:
public function isValidDirection($direction, $throwException = false) {
if(!in_array($direction, $this->getDirections()) && $throwException) {
throw new \InvalidArgumentException(sprintf('Invalid direction value. Valid directions are: "%s"', implode(", ", $this->getDirections())));
}
return in_array($direction, $this->getDirections());
}
Is this a bad idea? I've not come across this kind of pattern before and I'm wondering are there any pitfalls to it?
An exception should be thrown in exceptional circumstances. That means when your code is in a situation that it is not prepared to handle. If your function is a validation function whose job it is to confirm the validity of data, there should hardly be any exceptional error possible. The job of the function is simple: take input, return true or false depending on whether it's valid. If you want to handle the case of invalid input by throwing an exception and you want to DRY that repetitive check, create another function which wraps your validation function. So you'd have two functions: isValidDirection($input) and assertIsValidDirection($input), the latter of which throws an exception if it's not valid and otherwise does nothing.
function isValidDirection($input) {
return ...; // true or false
}
function assertIsValidDirection($input) {
if (!isValidDirection($input)) {
throw new InvalidArgumentException;
}
}
This keeps both functions' responsibilities clear and their implementation simple.
Yeah, it's a bad idea. If the method gets into a state where it can't continue or otherwise shouldn't get into it should throw an exception. It's up to the calling code to handle the exception as it feels is necessary or let the program crash. Otherwise the caller is oblivious to the program failing and will continue and usually make the situation worse/harder to debug.
If, in the case that you don't want to halt your program you can catch the exception and log an error, or handle it some more graceful way depending on your situation. If you don't expect the error at all the program will crash (ideally during testing) and the error won't propagate; you then know exactly where to look to fix it.
So, if I understand it correctly, your code should throw an exception if the $direction isn't in getDirections.
e.g:
public function isValidDirection($direction) {
if(!in_array($direction, $this->getDirections())) {
throw new \InvalidArgumentException(sprintf('Invalid direction value. Valid directions are: "%s"', implode(", ", $this->getDirections())));
}
return in_array($direction, $this->getDirections());
}
(Also, you don't need to call getDirections 3 times, just call it once and store it in a variable)
This is more of a architectural question. I like to know what people's opinion on how to properly handle errors in a fully Object Oriented PHP environment.
For example I have a class that retrieves all user data from the database. So I would use it in this way:
$userData = new UserDataConnection();
$userData->openDatabase();
$userData->retrieveData();
$userData->showData();
$userData->closeDatabase();
At each of these steps, an error could have potentially occurred. So would I return a boolean from each step stating whether the function has successfully executed (hence the error checking is within each function), or do I do a try-catch exception handling around the whole thing? or is there a better way?
Is it also better to always go to some kind of error page when some kind of error occur?
<?php
$ERROR = false;
try {
$userData = new UserDataConnection();
$userData->openDatabase();
$userData->retrieveData();
$DETAILS = $userData->showData();
$userData->closeDatabase();
} catch( Exception $e ) {
$ERROR = $e->getMessage(); // exit;
}
if( $ERROR ) {
$DETAILS = array();
}
?>
If you are using PDO you can throw a PDOException.
It typically boils down to a simple question:
May this function "legitimately" fail or is any failure a sign of something being really wrong?
If a function expects a certain kind of input and should never ever be called with a different kind of input, any failure to supply the correct input is an InvalidArgumentException. This is especially true for functions which do not directly handle user input. This works even better with type hinting.
If a function should always produce a certain result given the correct input, any failure of the function to produce that result is a RuntimeException or LogicException or some other kind of exception.
If a function may or may not produce some kind of result, false is a legitimate return value. Functions which deal with user input and therefore get very arbitrary input values are often fine with returning false.
Some examples:
getDatabaseConnection() is perfectly correct in throwing a RuntimeException or similar if it cannot establish a connection to the database. This is an exceptional circumstance in which case no work can continue.
transformFooIntoBar(Foo $foo) is correct in throwing some form of exception if it cannot return a Bar instance, for whatever reason that may be. The function has a clear purpose and a type checked input value. If it cannot do its job under such clear conditions, something is clearly wrong and must be fixed. Ergo, an exception.
checkIfUserExists($id) may well return false, because its job is to return a thumbs up or thumbs down. A user not existing is not an exceptional circumstance given this job description.
Where to catch a thrown exception depends on where you want to deal with it. Database connection errors should probably be caught at the very top of the call stack, since you probably cannot do anything if the database is down.
On the other hand, if some module is calling some submodule and half expects that submodule to fail and/or has a contingency plan in case it does fail, the module may catch the exception of the submodule and continue on doing its job. For instance getRSSUpdates() makes a call to a HTTP::fetchContents($url). If the URL returns a 404, the HTTP module may throw an exception, since it cannot return contents under these circumstances. The getRSSUpdates() function is prepared for this though and handles this case as "no updates at this time".
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
I'm kind of interested in getting some feedback about this technique I picked up from somewhere.
I use this when a function can either succeed or fail, but you'd like to get more information about why it failed. A standard way to do this same thing would be with exception handling, but I often find it a bit over the top for this sort of thing, plus PHP4 does not offer this.
Basically the technique involves returning true for success, and something which equates to false for failure. Here's an example to show what I mean:
define ('DUPLICATE_USERNAME', false);
define ('DATABASE_ERROR', 0);
define ('INSUFFICIENT_DETAILS', 0.0);
define ('OK', true);
function createUser($username) {
// create the user and return the appropriate constant from the above
}
The beauty of this is that in your calling code, if you don't care WHY the user creation failed, you can write simple and readable code:
if (createUser('fred')) {
// yay, it worked!
} else {
// aww, it didn't work.
}
If you particularly want to check why it didn't work (for logging, display to the user, or do whatever), use identity comparison with ===
$status = createUser('fred');
if ($status) {
// yay, it worked!
} else if ($status === DUPLICATE_USERNAME) {
// tell the user about it and get them to try again.
} else {
// aww, it didn't work. log it and show a generic error message? whatever.
}
The way I see it, the benefits of this are that it is a normal expectation that a successful execution of a function like that would return true, and failure return false.
The downside is that you can only have 7 "error" return values: false, 0, 0.0, "0", null, "", and (object) null. If you forget to use identity checking you could get your program flow all wrong. Someone else has told me that using constants like an enum where they all equate to false is "ick".
So, to restate the question: how acceptable is a practise like this? Would you recommend a different way to achieve the same thing?
I agree with the others who have stated that this is a little on the WTFy side. If it's clearly documented functionality, then it's less of an issue, but I think it'd be safer to take an alternate route of returning 0 for success and integers for error codes. If you don't like that idea or the idea of a global last error variable, consider redefining your function as:
function createUser($username, &$error)
Then you can use:
if (createUser('fred', $error)) {
echo 'success';
}
else {
echo $error;
}
Inside createUser, just populate $error with any error you encounter and it'll be accessible outside of the function scope due to the reference.
As long as it's documented and contracted, and not too WTFy, then there shouldn't be a problem.
Then again, I would recommend using exceptions for something like this. It makes more sense. If you can use PHP5, then that would be the way to go. Otherwise you don't have much choice.
A more common approach I have seen when exceptions aren't available is to store the error type in a 'last_error' variable somewhere and then when a failure happens (ie it returns false) look up the error.
Another approach is to use the venerable unix tool approach numbered error codes - return 0 for success and any integer (that maps to some error) for the various error conditions.
Most of these suffer in comparison to exceptions when I've seen them used however.
Just to respond to Andrew's comment -
I agree that the last_error should not be a global and perhaps the 'somewhere' in my answer was a little vague - other people have suggested better places already so I won't bother to repeat them
how acceptable is a practice like this?
I'd say it's unacceptable.
Requires the === operator, which is very dangerous. If the user used ==, it leads to a very hard to find bug.
Using "0" and "" to denote false may change in future PHP versions. Plus in a lot of other languages "0" and "" does not evaluate to false which leads to great confusion
Using getLastError() type of global function is probably the best practice in PHP because it ties in well with the language, since PHP is still mostly a procedural langauge. I think another problem with the approach you just gave is that very few other systems work like that. The programmer has to learn this way of error checking which is the source of errors. It's best to make things work like how most people expect.
if ( makeClient() )
{ // happy scenario goes here }
else
{
// error handling all goes inside this block
switch ( getMakeClientError() )
{ case: // .. }
}
Often you will return 0 to indicate success, and 1, 2, 3, etc. to indicate different failures. Your way of doing it is kind of hackish, because you can only have so many errors, and this kind of coding will bite you sooner or later.
I like defining a struct/object that includes a Boolean to indicate success, and an error message or other value indicate what kind of error occurred. You can also include other fields to indicate what kind of action was executed.
This makes logging very easy, since you can then just pass the status-struct into the logger, and it will then insert the appropriate log entry.
Reinventing the wheel here. Using squares.
OK, you don't have exceptions in PHP 4. Welcome in the year 1982, take a look at C.
You can have error codes. Consider negative values, they seem more intuitive, so you would just have to check if (createUser() > 0).
You can have an error log if you want, with error messages (or just arbitrary error codes) pushed onto an array, dealt with elegance afterwards.
But PHP is a loosely typed language for a reason, and throwing error codes that have different types but evaluate to the same "false" is something that shouldn't be done.
What happens when you run out of built-in types?
What happens when you get a new coder and have to explain how this thing works? Say, in 6 months, you won't remember.
Is PHP === operator fast enough to get through it? Is it faster than error codes? or any other method?
Just drop it.
When exceptions aren't available, I'd use the PEAR model and provide isError() functionality in all your classes.
Ick.
In Unix pre-exception this is done with errno. You return 0 for success or -1 for failure, then you have a value you can retrieve with an integer error code to get the actual error. This works in all cases, because you don't have a (realistic) limit to the number of error codes. INT_MAX is certainly more than 7, and you don't have to worry about the type (errno).
I vote against the solution proposed in the question.
It does make sense that a successful execution returns true. Handling generic errors will be much easier:
if (!createUser($username)) {
// the dingo ate my user.
// deal with it.
}
But it doesn't make sense at all to associate meaning with different types of false. False should mean one thing and one thing only, regardless of the type or how the programming language treats it. If you're going to define error status constants anyway, better stick with switch/case
define(DUPLICATE_USERNAME, 4)
define(USERNAME_NOT_ALPHANUM, 8)
switch ($status) {
case DUPLICATE_USERNAME:
// sorry hun, there's someone else
break;
case USERNAME_NOT_ALPHANUM:
break;
default:
// yay, it worked
}
Also with this technique, you'll be able to bitwise AND and OR status messages, so you can return status messages that carry more than one meaning like DUPLICATE_USERNAME & USERNAME_NOT_ALPHANUM and treat it appropriately. This isn't always a good idea, it depends on how you use it.
I like the way COM can handle both exception and non-exception capable callers. The example below show how a HRESULT is tested and an exception is thrown in case of failure. (usually autogenerated in tli files)
inline _bstr_t IMyClass::GetName ( ) {
BSTR _result;
HRESULT _hr = get_name(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _bstr_t(_result, false);
}
Using return values will affect readability by having error handling scattered and worst case, the return values are never checked by the code. That's why I prefer exception when a contract is breached.
If you really want to do this kind of thing, you should have different values for each error, and check for success. Something like
define ('OK', 0);
define ('DUPLICATE_USERNAME', 1);
define ('DATABASE_ERROR', 2);
define ('INSUFFICIENT_DETAILS', 3);
And check:
if (createUser('fred') == OK) {
//OK
}
else {
//Fail
}
Other ways include exceptions:
throw new Validation_Exception_SQLDuplicate("There's someone else, hun");),
returning structures,
return new Result($status, $stuff);
if ($result->status == 0) {
$stuff = $result->data;
}
else {
die('Oh hell');
}
I would hate to be the person who came after you for using the code pattern you suggested originally.
And I mean "Came after you" as in "followed you in employment and had to maintain the code" rather than "came after you" "with a wedgiematic", though both are options.
In my opinion, you should use this technique only if failure is a "normal part of operation" of your method / function. For example, it's as probable that a call suceeds as that it fails. If failure is a exceptional event, then you should use exception handling so your program can terminate as early and gracefully as possible.
As for your use of different "false" values, I'd better return an instance of a custom "Result"-class with an proper error code. Something like:
class Result
{
var $_result;
var $_errormsg;
function Result($res, $error)
{
$this->_result = $res;
$ths->_errorMsg = $error
}
function getResult()
{
return $this->_result;
}
function isError()
{
return ! ((boolean) $this->_result);
}
function getErrorMessage()
{
return $this->_errorMsg;
}
Look at COM HRESULT for a correct way to do it.
But exceptions are generally better.
Update: the correct way is: define as many error values as you want, not only "false" ones. Use function succeeded() to check if function succeeded.
if (succeeded(result = MyFunction()))
...
else
...