dealing with complex results in objects -- exceptions? - php

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.

Related

understanding exceptions

I have read articles upon articles trying to understand what exceptions are used for in php and I have gone through the answers already given in the forum. One of the answers which made atleast some sense to me is this one: Are exceptions in php really that useful?
Here is a simple function for finding the inverse of a integer with and without using exceptions (source):
With exception:
function inverse($x) {
if ($x==0) {
throw new Exception('Division by zero.');
} else {
return 1/$x;
}
}
try {
inverse();
}
catch (Exception $e) {
echo $e->getMessage();
}
Without exception:
function inverse($x) {
if ($x==0) {
echo "I'm zero. Don't let me be the denominator.";
} else {
return 1/$x;
}
}
So here is my question, why and when should I use one over the other?
why and when should i use one over the other?
Oh, this is easy: You should never use "without exception" :) Don't misuse return values as status flag. Thats a bad habit from earlier days and only makes things more complicated, because then you have to check the return values and even their types over and over again.
If you have a function like inverse() the only thing it should ever do is to "inverse". If it can't do it, it's an exceptional situation, thus (you may guess) an exception.
To sum it up: Throw an exception, when there is a situation, that prevent a function/method to work properly, and that the function/method is not able to handle itself.
There are various opinions on "when to use an exception". My personal opinion is:
If you are working with your own code, theres basically no need to throw exceptions, as you then need to write your own handler for it - which also can be done without throwing an exception.
If you are developing APIs that other programmers are using, it can be usefull to throw exceptions, so the developer using your code knows, that he has to take care of handling errors, AND gets an idea of what was the error-reason. (instead of just getting null he might catch NumberToSmallException, NotANumberException, ....)
In other words: When you already know how to handle an exception if it would appear - dont throw it. If the handling should be up to another developer, using your code - throw it.
Exceptions should not be used to control the flow of your application logic. Therefore use if / else statements.
But these are just my ten cents.
Especially when you use object oriented programming, exceptions are quite handy. For example, in an application where you use a DB library that throws exceptions for when it cannot make a connection. In that case, you can catch that exception somewhere, and you show a special page that tells the user that the database is not working.
Maybe the best usage of Exceptions happens when there a method calls more than one level.
Think like I call method A, then it calls method B, and it calls method C. When this happens, if you do not use exceptions, method A must know all different types of error messages of method B. And method B must know about C's in the same way. But by using exception, method C's error can be caught easily without the help of method A and B.
Exceptions should be used when your script encounters an error, in the example you can't divide by zero and so you have a logical error, so an exception would be appropriate.
Using exceptions allows you to see better errors messages and will help when it comes to debugging, rather than simply printing out a string which could be anything. Furthermore you can catch exceptions so you can detect when something goes wrong, whereas simply outputting a string isn't of much help.
Check out the PHP docs on this for more info.
Exceptions are an invaluable tool when writing complex and/or extensible pieces of software, but saying that return values aren't good for reporting anomalies is IMHO an oversimplified and even dogmatic approach.
In this specific case it's perfectly reasonable to return a null value, as in "the inverse of the argument does not exist". For me the most important point is that inverse does not actually do anything; it merely provides some information (i.e. it is "read-only", it has absolutely no side effects).
Note that "absolutely no side effects" is also a good rule of thumb which means that you should definitely not echo from within the function unless echoing is why it exists in the first place.
If there were an expectation that after calling inverse successfully the state of the program would have changed and inverse cannot perform this change for whatever reason (perhaps it got passed bad arguments; perhaps a resource it needs is not available; etc) then you should absolutely throw an exception and let the caller decide how to handle the error.
Think of it like this:
Sometimes, the value for $x comes from a user (eg. from an HTML form or something), in this case you would like to display an error (maybe something like "The frobing level needs to be different than zero").
Other times, you are getting the value from a database, in that case it's kind of useless to tell the user about frobing levels or stuff like that, you will want to show an error page and log detailed information somewhere on the server (or even send an email to an admin).
With the second example it's not really possible to control what happens in case of an error (the same message is printed each time).
The right thing to do is to let the code that is calling your function decide what happens in case of an error. Exceptions are one way of doing this.
There are 2 major benefits of using exceptions:
They go through the execution stack (meaning that if you have a few nested functions, you don't have to re-pass the error value, this is done automatically.
The first piece of code after a throw() statement is the code in a catch() statement. This means that you don't have to make hundreds of checks in every nested function/method you have.
Considering this functionality, using a return value is useful in simple cases (for example your case). In complex cases, where you have 10-20-30 different error messages that can appear in different levels in the execution stack, using exceptions is a must, or other developers(/even you in a few months) will have major problems when debugging.
That's my 2 cents on the issue, hope it helps.
PS: It's useful to log the exceptions in an exceptions.log.

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.

Trying to add a duplicate to a set - what kind of exception to throw?

I'm creating a method on a Doctrine model to add related objects to a collection, but I want to throw an exception when a duplicate object is added to that collection.
Here's the test(s):
public function testFluentInterface( )
{
$sport = new Sport();
$this->assertSame($sport, $sport->addCode('ANY'),
'Expected Sport to implement fluent interface.'
);
}
public function testCannotAddSameCodeMoreThanOnce( )
{
$code = 'BAZ';
$sport = new Sport();
$sport->addCode($code);
try
{
$sport->addCode($code);
$this->fail(
'Expected error when trying to add the same code to a sport more than once.'
);
}
catch( /*SomeKindOf*/Exception $e )
{
}
}
At first, I thought it might be appropriate for an OverflowException to be thrown in this case, but I'm not certain whether "this value already exists" is the same as "this container is full":
Exception thrown when you add an element into a full container.
There's UnexpectedValueException, but that seems to be more applicable to variables with incorrect types:
Exception thrown if a value does not match with a set of values. Typically this happens when a function calls another function and expects the return value to be of a certain type or value not including arithmetic or buffer related errors.
I could always use LogicException, but that seems a little generic for this use case:
Exception that represents error in the program logic. This kind of exceptions should directly lead to a fix in your code.
Is there a better choice here? Are my observations correct? What would be the most appropriate SPL exception to throw when trying to add a duplicate to a collection that must contain unique values?
There's no SPL exception that really fits. You might be better off creating your own Exception:
/**
* Raised when item is added to a collection multiple times.
*/
class DuplicateException extends RuntimeException {};
Throwing an exception in this case seems a bit drastic, somewhat equivalent to throwing an exception whenever you assign the same value to the same key in an array. Have you considered using a return value instead of an exception to detect this case?
As an example many classes in the Java Collection Framework (i.e. Set) do not throw an exception in such cases, they return false.
Personally I would go that way.
The more I think about it – especially in light of Toni's and Francis' respective answers – the more I wonder if throwing an exception is useful in this scenario.
Per Toni's point, many classes already handle this situation differently. Although returning a "failure" value is not an option in this case (the Sport class implements a fluent interface), attempting to add an object to a collection twice is not necessarily an "exceptional" case.
Francis also made a good point that other constructs in PHP – such as arrays - do not care about this sort of thing, either. Throwing an exception when a duplicate item is added to a collection would be unprecedented behavior that could lead to maintainability problems down the road.
Also, throwing an exception could be considered to be at odds with the concept of fluent interface. What would be the point of allowing the developer to chain methods on an instance if he has to break up the chain with conditional checks anyway?
In other words, if the goal is this:
$sport
->addCode($codeA)
->addCode($codeB)
->setSomeOtherProperties(...)
->save();
Then it makes no sense to force the developer to have to do this:
if( ! $sport->hasCode($codeA) )
{
$sport->addCode($codeA);
}
// etc. - Why bother having a fluent interface if it's unsafe to use it?
The above code is particularly problematic because addCode() is going to call hasCode() anyway, which in effect forces the developer to invoke duplicate computation.
And using a try/catch isn't much better:
try
{
$sport
->addCode($codeA)
->addCode($codeB)
->setSomeOtherProperties(...)
->save();
}
catch( LogicException $e )
{
// $sport is now in an unknown state.
}
Trying to recover from a LogicException in the above block is impractical, and it shouldn't even be necessary here; trying to add a code twice shouldn't be enough to stop the Sport object from being persisted.

when do I write my own exception class?

I have been wondering since I stepped into the murky waters of OOP and have written a couple or so of distributed libraries when it is necessary to write my own extension of the exception class.
So far I simply use the built in exception class and it seems to serve me well. Is it necessary, and if so when is it ok, for me to write an exception subclass.
You should extend the Exception class with your own Exception types when you need to differentiate between different types of errors. Throwing an Exception just means something went wrong. You have no idea what went wrong though. Should you abort everything? Is this an expected error? Throwing a UserIsNotAllowedToDoThisException instead means something much more specific. The importance is to differentiate what code can handle what kind of error:
try {
new Foo($bar);
} catch (UserIsNotAllowedToDoThisException $e) {
echo "Sorry, you're not allowed to do this.";
}
This code handles the simple case when something is not allowed. If Foo would throw some other exception, like TheDatabaseJustCrashedAndIsBurningException, you don't want to know about this here, you want some global error handler to handle it. By differentiating what went wrong, it allows you to handle problems appropriately.
OK, here a little more complete example:
First, if you use proper OOP, you need Exceptions to fail object constructions. Without being able to fail object constructions, you're ignoring a large part of OOP: type safety and therefore data integrity. See for example:
class User {
private $name = null;
private $db = null;
public function __construct($name, PDO $db) {
if (strlen($name) < 3) {
throw new InvalidArgumentException('Username too short');
}
$this->name = $name;
$this->db = $db;
$this->db->save($this->name); // very fictional DB call, mind you
}
}
In this example, we see a lot of things:
My User objects have to have a name. Failing to pass a $name argument to the constructor will make PHP fail the whole program.
The username needs to be at least 3 characters long. If it is not, the object cannot be constructed (because an Exception is thrown).
My User objects have to have a valid and working database connection.
Failing to pass the $db argument will make PHP fail the whole program.
Failing to pass a valid PDO instance will make PHP fail the whole program.
I can't pass just anything as the second argument, it needs to be a valid PDO object.
This means if the construction of a PDO instance succeeded, I have a valid database connection. I do not need to worry about or check the validity of my database connection henceforth. That's the same reason I'm constructing a User object; if the construction succeeds, I have a valid user (valid meaning his name is at least 3 characters long). I do not need to check this again. Ever. I only need to type hint for User objects, PHP takes care of the rest.
So, you see the power that OOP + Exceptions gives you. If you have an instance of an object of a certain type, you can be 100% assured that its data is valid. That's a huge step up from passing data arrays around in any halfway complex application.
Now, the above __construct may fail due to two problems: The username being too short, or the database is for whatever reason not working. The PDO object is valid, so the connection was working at the time the object was constructed, but maybe it's gone down in the meantime. In that case, the call to $db->save will throw its own PDOException or a subtype thereof.
try {
$user = new User($_POST['username'], $db);
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
}
So I'd use the above code to construct a User object. I do not check beforehand whether the username is at least 3 characters long, because this would violate the DRY principle. Instead, I'll just let the constructor worry about it. If the construction fails with an InvalidArgumentException, I know the username was incorrect, so I'll let the user know about that.
What if the database is down though? Then I cannot continue to do anything in my current app. In that case I want to halt my application completely, displaying an HTTP 500 Internal Server Error page. Here's one way to do it:
try {
$user = new User($_POST['username'], $db);
} catch (InvalidArgumentException $e) {
echo $e->getMessage();
} catch (PDOException $e) {
abortEverythingAndShowError500();
}
But this is a bad way. The database may fail at any time anywhere in the application. I do not want to do this check at every point I'm passing a database connection to anything. What I'll do instead is I let the exception bubble up. In fact, it has already bubbled up. The exception was not thrown by new User, it was thrown in a nested function call to $db->save. The Exception has already traveled up at least two layers. So I'll just let it travel up even further, because I have set up my global error handler to deal with PDOExceptions (it's logging the error and displays a nice error page). I do not want to worry about this particular error here. So, here it comes:
Using different types of Exceptions allows me to ignore certain types of errors at certain points in my code and let other parts of my code handle them. If I have an object of a certain type, I do not ever have to question or check or worry about its validity. If it wasn't valid, I wouldn't have an instance of it in the first place. And, if it ever fails to be valid (like a suddenly failing database connection), the object can signal by itself that an error occurred. All I need to do is catch the Exception at the right point (which can be very high up), I do not need to check whether something succeeded or not at every single point in my program. The upshot is less, more robust, better structured code. In this very simple example, I'm only using a generic InvalidArgumentException. In somewhat more complex code with objects that accept many arguments, you'd probably want to differentiate between different types of invalid arguments. Hence you'd make your own Exception subclasses.
Try to replicate this by using only one type of Exception. Try to replicate this using only function calls and return false. You need a lot more code to do so every time you need to make that check. Writing custom exceptions and custom objects is a little more code and apparent complexity upfront, but it saves you a ton of code later and makes things much simpler in the long run. Because anything that shouldn't be (like a user with a too short username) is guaranteed to cause an error of some sort. You don't need to check every time. On the contrary, you only need to worry about at which layer you want to contain the error, not whether you'll find it at all.
And it's really no effort to "write your own Exceptions":
class UserStoppedLovingUsException extends Exception { }
There, you have created your own Exception subclass. You can now throw and catch it at the appropriate points in your code. You don't need to do any more than that. In fact, you have now a formal declaration of the types of things that may go wrong in your app. Doesn't that beat a lot of informal documentation and ifs and elses and return falses?
The built in exception is good enough for almost every case. The only scenario that I could think of where you need another one is when there are more than one exception that can be thrown in a try and you want to do different things depending of which one is thrown. You have to distinguish two exceptions. therefore you need another one.
Only write it when you need it, e.g. to signal an own exception, for example if you code a library and no exception of the existing ones speaks the same.
See
Core PHP Exceptions
Core PHP SPL Exceptions
There are a lot of exceptions already build-in in PHP so for the normal program flow things should be covered exception-wise.
If you're developing a more complex system, like a parser, lexer plus compiler and everything is accessed via one routine/faced for it's API, the parser might want to throw a parser exception, the lexer a lexer exception and the compiler a compiler exception.
It can be useful to be able to differentiate. But I normally stick with the build in exceptions, it's easy to refactor later anyway in case it needs more differentiation.
And since there are namespaces nowadays, this is really freaking easy if you stick to the firsthand Exception class from the beginning ;)
IMHO:
Simply if you enter your own domain.
That is usually indicated when you need additional data to provide in your exception.
So actually you then also have to do you own class to add the additional class members.

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