As shown in the php documentation is it possible to create your own exception handler. I see this as a reasonable way to handle my user generated errors and exceptions throughout the project I am working on. Through research I have made a decent amount of progress in implementing a specific one, just for one class, including things like using ErrorException (from the first answer) and making sure to return false for error levels that I can't handle.
I have however run into a wall with making it more generic. I don't want to have to write a separate handler for every class I write (especially because the vast majority of that code is going to be the same for every one). Yet it feels like terribly bad practice to have every single error for the entire project in the same handler.
The closest I have gotten to what feels like an acceptable solution is to write a subclass of ErrorException for every class I want to handle the errors for and store messages in each of those. But even with this I am probably going about it wrong (I don't think that would be the proper place to store default error messages). Is there a universally accepted way of doing this that I have been unable to find? or is one of these ways actually the way it's generally done? or are there multiple solutions that are scalable based on the size of the project?
EDIT: Just realized I can write a generic Exception_Handler with the reused code and extend it for each set of errors I have (real herp moment for me), but it still seems like I should handle all errors in the same place. If I'm completely wrong, let me know.
EDIT 2: Decided to go with a config file containing the error messages for each class that will throw errors, then the name of the class that throws the error defines what config file is loaded to get the list of messages associated with error number. This also allows me to easily define messages that should get logged as opposed to messages that should get sent to the user (essentially specific vs. generic messages).
I guess I'll mark this as answered or something, but if I'm doing something wrong feel free to let me know, help is always appreciated.
Decided to go with a config file containing the error messages for each class that will throw errors, then the name of the class that throws the error defines what config file is loaded to get the list of messages associated with error number. This also allows me to easily define messages that should get logged as opposed to messages that should get sent to the user (essentially specific vs. generic messages).
More specifically I'll probably use an ini file that defines an array of arrays where each number contains the array of error messages for that error number. Then use a foreach with the thrown error numbers to return the error message(s).
Related
As a project gets bigger and bigger, I get a bit confused as to what types of exceptions should be thrown and where they should be caught, e.g. how to organize internal exceptions vs exception messages that should be shown to the end user. To keep confusion down, is it best practice to always catch an exception in the higher-level object?
Take this example: if I have a database class that inserts a row into the database, and that class is called by another object that processes data, and in turn this data processing object is called by a controller, is it correct to catch errors from the database class in the processing class, which (possibly) rethrows the error to be caught in the controller class? Or can an error thrown in the database class be caught in the controller class?
Additionally, if one method in the processing class is called by another method in the same class, and the first throws an error, is it ok to catch the exception in the same class? Or should it be deferred to the higher-level class that's calling it?
Are there any other tips on how to structure and organize exceptions in large projects with many levels of classes?
I like to think about exceptions as expected events that may interrupt your normal program flow but in an orderly and controlled way.
The task of your exception handling is to deal with this situation and resolve it in such a way that your program state remains valid and the application can continue.
Therefore you should add the exception handling at the first place up the calling hierarchy where you are actually able to resolve the situation.
This may include cleaning up previously opened resources which are now no longer needed, logging the event or providing feedback to the user.
In your example I would probably leave the handling logic to the controller.
The database often does not have enough context of what has just happened and how to deal with specific conditions since those depend on the context in which the database has been called.
Your controller on the other hand should have all context information and should be well aware of what the program just tried to do.
It is also probably better suited to resolve the issue for example by displaying a general error message to the user and maybe send detailed error report to the administrator.
Sometimes you will also have the situation where you need to catch exception on an intermediate level, to do some cleanup (like closing streams or rolling back some actions) and then rethrow the exception because you know that you did only resolve part of the situation.
All in all may general recommendation is to think about what actions need to be done to resolve such an exceptional event and then implement the error handling where those actions can be done easily.
An exception should be thrown in an exceptional event, i.e. if something is seriously wrong and the code cannot continue as is. E.g. database is down, remote service is not responding, seriously malformed input received.
If you catch an exception, you need to know what to do with it. When an exception has been raised, it means your application is in a serious error state. If you catch the exception, you should have a serious plan on how to proceed from this error state. If you don't have a plan, there's no point in catching it. If the database is down, you will probably want to stop the program. On the other hand, if a remote HTTP request yielded a 404 response and your HTTP handler is throwing that as an exception, you will probably be able to live with that error and continue (depending on what that request was supposed to be used for).
Raw exception messages should never be shown to endusers. The exception needs to be logged, but the enduser should only see a generic nice "Oops, something went wrong, maybe you want to try X instead...?" message. This is not specific to exceptions, it's just good UX design.
I've created a simple class LogHelper with a static method that I call within my application. I can call it as follows:
LogHelper::writeToErrorLog($config->getLogPath(), $exception); or
LogHelper::writeToErrorLog($config->getLogPath(), $exception, $config->getLogFile);
The writeToErroLog method will generate a log filename if one isn't passed into it.
I have another class called Config, which basically takes an XML file and exposes the values via getters & setters. This is initialised at the start of the app & contains the log path where the error logs need to be written to.
My requirements are that I create one log file with the same filename per run of the application. When the app ends the logs, if populated, will be emailed.
My application has numerous other classes for DB, parsing data, formatting data, etc... all requiring logging at some point. The majority of my errors will come from exceptions thrown which will bubble up to the parent class, caught & handled by the LogHelper. There will be several cases where I don't want to throw exceptions and will just want to log information or errors.
My concern is that I feel like I'm constantly passing the config to every class that requires logging, which feels wrong. In addition I only want to be setting the filename for the error log once. Is there any best practice way of approaching this?
TIA
Stuff
Have you considered using set_exception_handler()? You wouldn't have to put the logger in every class, it would simply handle all uncaught exceptions. You could call it within your bootstrapping process or some other application initialization spot as such:
set_exception_handler(array("MyClassName", "functionNameHere"));
Inside that function you could call LogHelper::writeToErrorLog().
I have a question regarding error handling in Zend. I am fairly new to zend frame work.
I am new on this project that i am working on and the previous developers didn't handle service errors and the application is fairly large so I am trying to figure out an easy way to handle all the errors the service returns, and even handle the errors when service fails.
so when ever there is an error we need to alert the user that something is wrong and show the error.
now since i will be getting that in Model, how do I handle this in elegant way so that there is not much rework to be done.
Can i create a common class and extend it? I also need to alert the user in case of any error.
I want a better way because I have more than 150 controller files and about more than 100 model files.
Thanks
For a ZF app that's using Zend_Application, you should ensure that your application.ini file has this in it:
resources.frontController.throwExceptions = false
Then any Exception that is thrown will be trapped and the ErrorController's errorAction() method will be called. This gives you a centralised place to handle errors.
The whole "when to throw exception or return value" questions has been asked a lot (see the following to see just one example):
Should a retrieval method return 'null' or throw an exception when it can't produce the return value?
and I completely agree with the answers in main.
Now my question arises from adding a little more context to the above when applying this to a more complex system. Ill try and keep this as brief and simple as possible.
Right we have an example MVC PHP application:
Model A: has a function get_car($id) which returns a car object.
Controller A has a simple function for say showing a car to the user
Controller B however has a complex function that say gets the car, modify it (say through one of model A's set functions) and also updates other tables based on some of these new values through other models and libraries throughout the system - very complex ay lol
we now get to the main part of my question:
For data integrity I want to use MySQL transactions. This is where I run into a "what's best / what's best practice" scenario...
We write Model A to return FALSE if the car is not found or there is an SQL error.
This is fine for Controller A as it just wants to know if there was a error and bom out, so we just check the return value an bom - fine.
We now get to Controller B. Controller B say does some database updating before the Model A function is called which we need to roll back on error so we need to use a transactions. now this is where I get to my problem. do I leave Model A as a return value and just check it or do I change it to throw exception with the knock on effect of then having to also re-write Controller A as we now need to catch the exception... then (not done yet ;o)) do I roll back in the catch of the model (but how do we know if a transaction has been used or not?) or do we catch and re-throw or allow to bubble up to the controller catch and do the roll back there?
what I'm trying to say is that if I have lots of models and controllers with database interaction should I just make them throw exceptions and then wrap all my other code eg controller functions in try catches encase the model or library functions ever throw, or, do I make the models "self contained" to tidy and handle there own problems but then what do I do about rolling back a transaction if (for this "call") one was open (as per my example above not every time is a transaction opened...)? if this was the case I would have to make all my functions return something and then check this in the controller, as this is the only place that knows if there is an open transaction or not...
So to clarify I can use a try catch to catch and roll back in a controller, that's ok, but how to I do this from "further down" eg in a model or library function... that could be called both during and transaction or just as an auto commit normal MySQL call?
An explained answer would be great (as I like to understand why I am doing something) but if not a some vote for the favourite of the follow solutions (well the solutions I can see):
1) make all model and library functions always return a value and then the controller can either just bom or do a try catch to roll back where necessary - but meaning that I would have to check the return value of every model and library function everywhere they are used.
2) make all model and library functions throw exceptions (say on SQL error) and wrap every controller (which would call the model and library functions) in a try catch where the catch would either just bom or roll back if necessary...
also please note "bom" is push user somewhere or show a pretty error (before someone says "its bad practice to just allow your application to die..." lol)
I hope you get where Im coming from here and sorry for the long loooooong question.
Thanks in advance
Ben
[There's a theoretical problem implicit in the "For data integrity I want to use MySQL transactions"... since MySQL historically hasn't been very ACID - PostgreSQL and Oracle both provide stronger support for ACID. However, back to the real question...]
Both your (1) and (2) focus on exceptions versus failure-return values, but my impression is that this isn't the key part of detangling exceptions, error returns, and open transactions (and some databases support SQL exceptions as well). Instead, I'd focus on keeping the transaction state tied to the nesting of the functions manipulating the model. Here are some thoughts along this line:
You will probably always have error returns from some library functions anyway, so having Model A return FALSE isn't really breaking the paradigm, nor is there anything particularly troublesome about a mix of error returns versus exceptions. However, error returns MUST bubble up correctly - or be converted to exceptions if they go beyond what can be locally address.
Nested transactions are the most obvious way to have one controller start a database manipulation and still call other stuff in the app that also uses transactions. This allows a failed sub-sub-function to abort just its own part transaction and take either the error return or exception approach to bubbling the error up on the non-SQL side while the closed sub-transactions still maintain reasonable matching state. This usually needs to be simulated in code outside of the database (this is essentially what Django does).
Your code could start a new (potentially large) transaction, and keep track of the fact that it's already open to keep the sub-sub-functions in your code from trying to reopen it.
In some databases, code can detect whether a transaction is already open based on the database session state, allowing you to check the DB session state instead of tracking it in code.
Both of the above allow one to use savepoints to simulate truly nested transactions.
One must be very careful to avoid calling SQL calls with implicit commits (CREATE TABLE, for example). MySQL probably deserves a lot more caution around this issue than, say, PostgreSQL.
One way to implement the one big transaction approach is to have high-level function that initiates the transaction and then itself calls the top of whatever Controller B needs to do. This makes either bubbling up errors or having a special abort-transaction exception pretty straightforward. Only the top function would call commit rather than abort if no subfunction failed and no exception was caught. Subfunctions wouldn't call commit.
Conversely, you could have all of your functions pay attention to transactional depth implemented in the non-SQL side (your code), although this is harder to set up in some languages than others (it's pretty easy using decorators in Python, for example). This would allow any of them to call commit if they were done and the transactional depth at zero.
Hope this helps someone :-)
I have my own AppCotroller and using the beforeRender method to make changes to $this->viewPath based on the desired output format.
Is there a way I can check if Cake is currently outputting an error message? If I change the viewPath and then it's displaying an error (like can't load model, etc) it will error on the error :)
By the time Cake is displaying the error it should already be too late to do something about it. Not quite sure why you'd get an error about missing models when you change the viewPath, I hope that was just an example.
You might have some luck overriding or extending the ErrorHandler to intercept errors, but I wouldn't recommend doing that. Errors don't exist to be hidden, they're there to tell you something.
Creating a custom View might be a good idea depending on what you want to do (see the MediaView as an example of an alternative view).
The best thing to do though should be to avoid triggering errors by only allowing certain, predefined views to be set or making sure that a certain view file exists before trying to invoke it.