so, instead of lots of instances of
if (odbc_exec($sql))
{
}
else
{
myErrorHandlingFunction();
}
I wrap that in a function
function myOdbxExec($sql)
{
if (odbc_exec($sql))
{
}
else
{
myErrorHandlingFunction();
}
}
BUT I would like myErrorHandlingFunction() to report things like __LINE__ __FILE__ etc
Which looks like I have to pass thoses infos to every call of helper functions, e.g. myOdbxExec($sql, __FILE__, __LINE__) which makes my code look messy.
function myErrorHandlingFunction($errorTExt, $fiel, $line)
{
// error reporting code goes here
}
function myOdbxExec($sql, $file, $line)
{
if (odbc_exec($sql))
{
}
else
{
myErrorHandlingFunction();
}
}
$sql = 'select * from ... blah, blah, blah...';
myOdbxExec($sql, __FILE__, __LINE__); // <==== this is *ugly*
In C I would hide it all behind a #define, e.g. #define MY_OFBC_EXEC(sql) myOdbxExec(sql, __FILE__, __LINE__)
1) (how) can I do that in PHP
2) what else is worth outoputting? e.g. error_get_last()? but that has no meaning if odbc_exec() fails ...
To rephrase the question - what's the generic approach to PHP error handling? (especially when set_error_handler() doesn't really apply?
Edit: just to be clear - I do want to handle exceptions, programming errors, etc, but, as my example shows, I also want to handle soemthings the teh PHP interpreter might noit consider to be an error, like odbc_exec() returning false().
Both the above answers mentioning debug_backtrace are answering your _______LINE_____ / _______FILE___ question with the debug_backtrace() function. I've wanted this answer too in the past, so have put together a quick function to handle it.
function myErrorHandlingFunction($message, $type=E_USER_NOTICE) {
$backtrace = debug_backtrace();
foreach($backtrace as $entry) {
if ($entry['function'] == __FUNCTION__) {
trigger_error($entry['file'] . '#' . $entry['line'] . ' ' . $message, $type);
return true;
}
}
return false;
}
You can then call, for instance, myErrorHandlingFunction('my error message');
or myErrorHandlingFunction('my fatal error message', E_USER_ERROR);
or try { ... } catch (Exception $e) { myErrorHandlingFunction($e->getMessage()); }
First off, you might want to consider using exception handling.
If for some reason, that doesn't appeal to you, you can use debug_backtrace inside your generic error handler to figure out where the handler was called from.
EDIT In response to OP's comment:
Exceptions don't have to come from PHP built-ins. You can throw your own. Since an ODBC error generally is an exceptional condition, just throw an exception when you detect one. (And catch it at some higher level).
<?PHP
if (! odbc_exec($sql) )
throw new DatabaseException('odbc_exec returned false, that bastard!');
Use debug_backtrace to figure out where a function was called from in your error handler. Whether you invoke this error handler by manually calling it, by throwing and catching exceptions, PHPs error_handler or any other method is up to the application design and doesn't really differ that much from other languages.
Related
In the PHP project I'm working on there are several methods that make use of individual try/catch blocks. Here is one example:
public function getListData()
{
$clauses['filter'] = '';
$clauses['sort'] = 'CAST(propertyID AS INT) DESC';
try
{
return $this->getModel()->getListData($clauses);
}
catch (Exception $e)
{
// create an Error() object, send $e->getMessage() to it
}
}
Now, keeping in mind there are several similar methods, it would seem more efficient to write a method in the Model class that would look like this:
public function run($method)
{
try
{
return $this->$method;
}
catch (Exception $e)
{
//create an Error() object, send $e->getMessage() to it
}
}
The problem is calling it. This does not work:
public function getListData()
{
return $this->getModel()->run('getListData($clauses)');
}
The error is:
Undefined property:
classes\utility\Model::$getListData($clauses).
Is there a way to get this to work?
I'm going to assume that the first and second getListData() methods are in separate classes, otherwise you are calling a loop, since getListData would call getListData...which would call, you get it.
However, the way you are calling the method is incorrect in the run() method. It should be called using call_user_func. It is a callback to the method, not a call to the property, of the class.
You could call it statically using
public function run($method, $data)
{
try
{
return call_user_func(array($this, $method), $data);
}
catch (Exception $e)
{
//create an Error() object, send $e->getMessage() to it
}
}
public function getListData()
{
return $this->getModel()->run('getListData', $clauses);
}
There are several problems with this approach:
It prevents you from listening for custom exceptions
You can throw exceptions other than Exception, but this type of wrapper will make it much more difficult to do so.
It is difficult to follow the execution flow
When you pass method names and parameters around as strings, it becomes much harder for humans, IDEs and code analysis tools to understand what the program will do at runtime.
Try/catch blocks are cheap
The code required to catch exceptions is very simple and easy to use. This wrapper adds more complexity and more cost (an extra function call).
Consider just using try/catch blocks where needed instead of using the wrapper. If you have fifty similar methods as described in your comment above, you may gain more efficiency by eliminating the duplicate business logic and combining those methods.
You could simply convert errors to exceptions using this code:
set_error_handler(function ($errno, $errstr, $errfile, $errline)
{
if ((error_reporting() & $errno) === $errno)
throw new \Exception("$errstr ($errfile: $errline)", (int) $errno);
}, -1);
After it any error would be converted to exception.
Consider a function hierarchy, Function Four() Calls Three() which calls Two() Which again calls One() to do the job:
Function One($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
}
// .......... Do the Job ................
}
Function Two($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
} else {
One($x);
}
}
Function Three($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
} else {
Two($x);
}
}
Function Four($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
} else {
Three($x);
}
}
If I call four with a String value it will cause an Exception to occure.
Now consider following code with Exception in parent function only.
Function One($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
}
// .......... Do the Job ................
}
Function Two($x) {
One($x);
}
Function Three($x) {
Two($x);
}
Function Four($x) {
Three($x);
}
Here, I call Four() and pass a string, it will also cause an Exception to occure.
So which one is the best practice and why?
When I start writing code I end up writing a lot of exception handling, plz help.
If the functionality in function one needs $x and that is the only function that uses $x you can throw the exception only in function one. I assume function two, three and four will also do other things (otherwise they are useless). In that case you should check the value also in those functions. If they do not already use $x they may do in the future. In that case it is easy to forget to check the $x value and a bug is born.
IME it's good practice to fail as close to the problem as possible. That being said, I think option 1 is the way to go. This makes it so that when the exception occurs, you have confidence that it was the call to Four that was the problem and you can debug from there. Option 2 is easy but you don't know if the problem lies in Four, Three, Two or One. As your software grows in complexity so will your time debugging.
an alternative, i would know the trace and you can use as
Function One($x) {
if(!is_int($x)) {
throw Exception("X must be integer");
}
// .......... Do the Job ................
}
Function Two($x) {
try
{
One($x);
}
catch(Exception $e)
{
throw $e;
}
}
Function Three($x) {
try
{
Two($x);
}
catch(Exception $e)
{
throw $e;
}
}
Function Four($x) {
try
{
Three($x);
}
catch(Exception $e)
{
throw $e;
}
}
in this case you can know where is the error start, and only 1 is_int check.
I think it depends largely on what the functions are meant to do.
If the value of x is critical to the function, then the exception should be handled in that function. If it is just used for passing parameters, then you can let it slip through to the last function.
I am not sure of how the engine evaluates the function processing, but mostly it will push its contents onto the stack and then make the necessary jump, which in turn causes delay, so better to incorporate the exception handling then and there, when the values are generated, rather than letting it flow uselessly till it is being used just to save useless processing time.
Generally an exception means you have wasteful computation. So model 1 will make sure you don't do so.
Server Processing is precious to all... :)
go here and you may find the answer:
I'm testing some legacy code that extends the default php exception object. This code prints out a custom HTML error message.
I would like to mock this exception object in such a way that when the tested code generates an exception it will just echo the basic message instead of giving me the whole HTML message.
I cannot figure out a way to do this. It seems like you can test for explicit exceptions, but you can't change in a general way the behavior of an exception, and you also can't mock up an object that extends a default php functionality. ( can't think of another example of this beyond exceptions... but it would seem to be the case )
I guess the problem is, where would you attach the mocked object?? It seems like you can't interfere with 'throw new' and this is the place that the object method is called....
Or if you could somehow use the existing phpunit exception functionality to change the exception behavior the way you want, in a general way for all your code... but this seems like it would be hacky and bad....
EDIT: here is some code to make things clearer:
class FooTest extends PHPUnit_Framework_TestCase{
public function testBar(){
include '/path/to/file.php'; //generates exception
$this->assertTrue($baz);
}
}
...
//overridden exception class
class Foo_Exception extends ErrorException{
...
so, my question, is there a way to deal with this overriden class, without doing it on a case by case basis? what if I'm not testing the behavior of the exception, just the code that causes the exception?
I would first write a test that captures the exception generation behavior:
include '/path/to/file.php'; //generates exception
public function testCatchFooException() {
try {
$this->assertTrue($baz);
}
catch (Exception $expected) {
$this->assertEquals('This is expected html from exception', $expected->getMessage());
return;
}
$this->fail('An expected Exception has not been raised Foo_Excpetion.');
}
Now you can do several things with this coverage test. You can either fix up the exception, or fix the code that causes the exception.
Another thing you can do is wrap the entire file.php in a class:
class FooClass {
function runFoo() {
include '/path/to/file.php'; //generates exception
}
}
Then add tests while using extract method until you isolate exception.
[EDIT]
Here is some serious procedural legacy code:
<?php
require_once 'helper.php'; //helper file
function countNewMessages($user_id) {
}
function countNewOrders() {
}
function countNewReturns() {
}
function getDB($init = NULL) {
}
function getDisplay() {
}
getDisplay();
?>
And here is the wrapped class:
<?php
require_once ''; //helper file
class Displayer {
function countNewMessages($user_id) {
}
function countNewOrders() {
}
function countNewReturns() {
}
function getDB($init = NULL) {
}
function getDisplay() {
}
}
?>
And now I can test it:
function testGetDisplay() {
$display = new Displayer();
$this->assertEquals('html code', $display->getDisplay());
}
And test the individual functions in it. And if I can further sprout methods on it.
The above test would be considered a coverage test. There may be bugs in it, but that is what it does. So as I sprout methods the get more code coverage from tests by sprouting that I can make sure I don't break the output.
The extened PHP exception object "prints" a costum HTML error page? You mean its error message is an entire HTML page? That's not very clever...
What you can do about it is to replace the default exception handler (see this function), call getMessage on the exception and parse the HTML error page to extract the message. Then you can print the error message and kill the script. Like this (in PHP 5.3):
set_exception_handler(
function (Exception $e) {
die(parse_html_error_page($e->getMessage()));
}
);
OK, I misunderstood the question. If the script you're testing catches the error and then echoes an error page, then this has nothing to do with exceptions. You can use the ob_ family:
ob_start();
include $file;
$contents = ob_get_contents();
if (result_is_error($contents))
die(extract_error_from_result($contents));
else
echo $contents;
ob_end_clean();
Which would you recommend?
Return an error code, such as E_USER_ERROR from a function, and determine proper message higher up:
function currentScriptFilename()
{
if(!isset($_SERVER['SCRIPT_FILENAME']))
{
//This?
return E_USER_ERROR;
}
else
{
$url = $_SERVER['SCRIPT_FILENAME'];
$exploded = explode('/', $url);
return end($exploded);
}
}
Execute trigger_error() from the function, with a specific error message:
function currentScriptFilename()
{
if(!isset($_SERVER['SCRIPT_FILENAME']))
{
//Or this?
trigger_error('$_SERVER[\'SCRIPT_FILENAME\'] is not set.', E_USER_ERROR);
}
else
{
$url = $_SERVER['SCRIPT_FILENAME'];
$exploded = explode('/', $url);
return end($exploded);
}
}
I am not sure if I will regret having put a bunch of error messages in my functions further down the line, since I would like to use them for other projects.
Or, would you recommend something totally different?
Do not mix the matters.
Error notification and error handling are different tasks.
You have to use both methods simultaneously.
If you think that $_SERVER['SCRIPT_FILENAME'] availability is worth an error message, you can use trigger error. However PHP itself will throw a notice if you won't check it.
If you want to handle this error, just check this function's return value.
But I would not create a special function for this task.
So,
if (!$filename = basename($_SERVER['SCRIPT_FILENAME']) {
// do whatever you want to handle this error.
}
would be enough
Exceptions could be useful to handle errors, to know if we had any errors occurred.
A simple example:
try {
$filename = basename($_SERVER['SCRIPT_FILENAME'])
if (!$filename) throw new Exception("no filename");
$data = get_some_data_from_db() or throw new Exception("no data");
$template = new Template();
//Exception could be thrown inside of Template class as well.
}
catch (Exception $e) {
//if we had any errors
show_error_page();
}
$template->show();
3.Use exceptions.
If this is the route you are going, I'd rather recommend throwing Exceptions rather then returing an E_ERROR (E_USER_ERROR should be used), as this is just an integer, and possibly a totally valid return for your function.
Advantages:
- Throwing of an Exception cannot be interpreted as anything else then an error by mistake.
- You keep the possibility to add a descriptive error message, even though you don't handle the error at that point/
- You keep a backtrace in your Exception.
- You can catch specific exceptions at specific points, making the decision where in your project a specific type of error should be handled a lot easier.
If not using exceptions which you should be, use trigger_error().
If it is an error you'd like to deal with, try returning FALSE like a lot of the in built functions do.
If you do use exceptions, catch them like this
try {
whatever()
} catch (Exception $e) {
// handle however
}
I have come accross to this function below and I am wondering wether this is the right way of using the error handling of try/catch.
public function execute()
{
$lbReturn = false;
$lsQuery = $this->msLastQuery;
try
{
$lrResource = mysql_query($lsQuery);
if(!$lrResource)
{
throw new MysqlException("Unable to execute query: ".$lsQuery);
}
else
{
$this->mrQueryResource = $lrResource;
$lbReturn = true;
}
}
catch(MysqlException $errorMsg)
{
ErrorHandler::handleException($errorMsg);
}
return $lbReturn;
}
Codewise it is correct/works, However the power of try-catch is that when an Exception is thrown from deep down in one of the functions you're calling.
Because of the "stop execution mid-function and jump all the way back to the catch block".
In this case there are no deep-down exceptions therefore I would write it like this:
(Assuming there is a function "handleErrorMessage" in the ErrorHandler.)
public function execute() {
$lsQuery = $this->msLastQuery;
$lrResource = mysql_query($lsQuery);
if(!$lrResource) {
ErrorHandler::handleErrorMessage("Unable to execute query: ".$lsQuery);
return false;
}
$this->mrQueryResource = $lrResource;
return true;
}
Which I find more readable.
No. Throwing an exception in this case is simply a GOTO, but with a (slightly) prettier face.
Why have a call to ErrorHandler::handleException here anyway?
Just throw the exception, but never catch it. Then in the global initialization code for your app have a function with the following signature:
function catchAllExceptions(Exception $e)
Then call:
set_exception_handler('catchAllExceptions');
This will cause all uncaught excpetions to be passed as an argument to catchAllExceptions(). Handling all uncaught exceptions in one place like this is good, as you reduce code replication.
Well it is not really a good implementation since you throw the exception and you look for that exception in catch. So the answer of Visage is true.
You should use a global error handler instead of a tr-catch usage like in your code.
If you are not sure of the type of the error and occurance but want to continue the execution of the code although an exception had occured, then a try-catch block will help.