I'm building a newsletter CMS and I want to loog any errors to a database with information like timestamp, error, userID and function info. What's the best way to do this?
I'm thinking I should build a class that handles the errors and inputs them into a MYsql table using PDO.
pseudo code:
class sbmtErr
{
private $errStrng;
protected function sndErr($err, $usrData, $mthd){
$sndErrPDO = new myPDO;
$this->errStrng = "INSERT INTO errTbl (error, userID, method) VALUES ('".$err."', ".usrData['usrID'].", '".$mthd."')";
$sndErrPDO->sqlQry($errStrng);
}
}
My problem here is I don't know how to isolate the method that threw the error.
Is there a better way to do this?
Thanks.
Extend the exception class. CMSErrorException , when thrown (i.e. On construct) use reflection to find out things like function, line number, etc. how you find the user's id depends on how you keep it.
Then, regardless of what you do when you catch it, you call a method (again from the construct) which logs it into the database.
Careful not to throw these custom exceptions inside of the exception code, as it might cause an infinite loop in case of a database error.
Related
I'm writing a library which requires a database connection, so it requires users to pass a PDO object as a parameter of the constructor.
But as many of you know, PDO has 3 different error reporting mechanisms: Silent mode, warning mode and exception mode (http://www.php.net/manual/en/pdo.error-handling.php).
The problem is that each mode requires a different type of error handling code. Accepting that I can't force the user to use my preferred mode, i think that my options are:
Setting my preferred mode on the inputted PDO object, and worrying about nothing
Cloning the inputted PDO object and then setting my preferred mode
Writing error handling code for all 3 modes and then detecting and employing the appropriate one with the help of PDO::getAttribute() method
Setting my preferred mode before each method call and then revoking it after each one
So 1 can break user's code, 2 looks like unnecessary duplication, 3 is terribly awkward, and 4 is not-so-terribly-awkward-but-still-awkward and still susceptible to breaking user's code.
So i'm asking to library writers out there, how do you handle this?
Ok, not sure if this is the right site for this sort of question, but first, let me give you the short run-down of your options, and tell you what IMO is the better option. Then I'll explain all of it in future edits.
That's not the way forward. The user is passing an instance, which you then change, behind the users' back. Don't change what isn't yours
Don't clone a DB connection. Just don't
A library shouldn't deal with errors that are the result of the user's code. That's the user's problem/fault, they should then also deal with it. No way a lib can anticipate on every possible abuse
No, really... This is just a silent way of doing what you're doing in point 1: changing an object you never really owned.
What, then, would I do? Simple: Provide an API for DB connections that could, in its heart have a PDO instance, but then at least the user has a clear API, and knows what the result of possible errors are (for example PDO + setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) => your API will always throw exceptions
Now, why is your first option not a viable approach? (again: this is all my opinion)
Suppose I were to use your code, and have something like this:
//code
$this->db = new PDO($dsn, $usr, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT));
$this->dependency = new Your\Lib\Stuff($this->db);
//code
$this->db->query('bad query');
Now if you set PDO to throw exceptions, I'm not catching any. My code wasn't writtin in a way to deal with PDOException instances, so it'll cause the entire app to grind to a halt. What's more, who's to say that I'm not going to add this line, while debugging, when that happens:
$this->dependency = new Your\Lib\Stuff($this->db);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);//override your setting
This isn't a safe path to go down, so don't.
Next: cloning PDO just won't work. If you have a silly person who wrote his own class to extend from PDO, this is possible:
class BadIdea extends PDO
{
public function __clone()
{//disable clone
return false;
}
}
In this case $db = new BadIdea() will still pass as an instance of PDO (test function foo(PDO $arg){echo 'argument is instance of PDO';} and then call foo(new BadIdea), it will work). Now you can't clone, and your lib fails.
A lib or framework should be written generically enough so you can reuse it. If you're writing the code, while thinking of a particular use-case in mind, you're probably going find yourself editing the code every time you wish to use it again.
Unless you're going to be creating your own lib (in which case the user wouldn't have to pass a self-made DB connection anyway), error handling shouldn't be the task of your lib.
Your code should just throw exceptions when something happens that is unexpected. You can't be expected to write code that deals with all of these situations:
$yourInstance->pass('Invalid query');
$yourInstance->select('INSERT ...');//valid query, wrong method
$your instance->query(array('invalid', 'argument'));
Or worse:
try
{
$yourInstance->beginTransaction();
$yourInstance->query($q1);
$q2 = $anotherObj->composeComplexQuery();//might be the cause of Exceptions, too
$yourInstance->query($q2);
$yourInstance->commit();
} catch(){}
When you deal with errors inside of your lib, then how will your user be able to deal with situations like these? a transaction is a concious decision made by the user, any exception that might occur during a transaction, be it an error in the queries or an exception thrown by third-party methods can result in the transaction having to be rolled back.
Your lib's scope isn't wide enough to pick up on the exceptions that are thrown in the user's code.
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.
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 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.
I've been developing a web application with PHP and MySQL. The other day, I made some changes to the database and adapted one page to the new table layout but not another page. I didn't test well enough, so the site went online with the error still in the other page. It was a simple MySQL error, and once one of my co-workers spotted it, it was a simple fix.
Now that it's happened, I'd like to know how I can catch other MySQL errors. I'm thinking about some sort of notification system, that would send me an email when a mysql_query() fails.
I understand, of course, that I wouldn't be notified until after the error occurred, but at least I would have been notified immediately, rather than my co-worker come tell me after who-knows-how-many other people had run into the same fatal error.
Is there some sort of way to put in a hook, so that PHP automatically runs a function when an error happens? Or do I need to go through my code and add this functionality to every location where I use mysql_query()?
If the latter, do you have any recommendations on how to prevent something like this in the future? If this is the case I'll probably create a class to abstract SQL operations. I know I should have been doing this the whole time... But I did organize my sets of functions into different include files, so at least I'm doing most things right. Right?
You could use a wrapper function like this:
function mysql_query_wrapper($query, $link=null)
{
if (is_null($link)) {
$result = myql_query($query);
} else {
$result = myql_query($query, $link);
}
if (mysql_error($result)) {
// error occurred
}
return $result;
}
Then you just need to replace each mysql_query call with mysql_query_wrapper.
You can use custom functions for error handling using set_error_handler().
However, mysql_query won't trigger an error, but return false. The errors turn up only afterwards when trying to work with the results. In this case it might be better to define a custom wrapper function that calls mysql_query() and outputs possible errors using mysql_error(). That way, you can immediately halt your application on an error if so desired.