4

I hope the title isn't too confusing, I'll try to explain better below.

Suppose I have a function in a separate file, functions.php:

function divide($num1, $num2) {
    if ($num1 == 0 || $num2 == 0) {
        trigger_error("Cannot divide by 0", E_USER_ERROR);
    } else {
        return ($num1 / $num2);
    }
}

And another file that calls it:

include "functions.php";

echo divide(10, 0);

My error is

Fatal error: Cannot divide by 0 in C:\Users\Derek\Desktop\projects\functions.php on line 5

My question is, how do I make that error instead point to the location of the error in the main code, so I instead get:

Fatal error: Cannot divide by 0 in C:\Users\Derek\Desktop\projects\main.php on line 3

The particular reason I want this is because I have a function called load_class that simply finds a PHP file and instantiates the object inside, but if given an incorrect file name, it reports an error from inside load_class, which is technically true, but it's not particularly helpful if I don't remember where I called load_class in the first place. I would like the error to point to the file that called load_class incorrectly.

Also, I would like to write a function error() (something like below) that when given a message as a parameter would throw more "meaningful" error messages, but when done that way, the error always says it comes from error(), not from where the error actually came from!

For example, in an error.php:

/**
 * error()
 * 
 * Throws an error of a certain type
 * 
 * @param  string $type    The type of error. "Fatal", "warning," or "notice"
 * @param  string $message A description of the error
 * @return void
 */
function error($type, $message) {
    switch (strtolower($type)) {
        case 'fatal':
            trigger_error($message, E_USER_ERROR);
            break;
        case 'notice':
            trigger_error($message, E_USER_NOTICE);
        default:
            trigger_error($message, E_USER_WARNING);
            break;
    }
}

And in an index.php

error("fatal", "A sample warning!");

My error given is:

Fatal error: A sample warning! in C:\Users\Derek\Desktop\projects\synthesis\sys\Error.php on line 45

But the error didn't occur in error.php, it happened in index.php! How can I make it show where it really came from?

Derek Maciel
  • 1,275
  • 2
  • 12
  • 19

5 Answers5

2

The debug_backtrace function allows you to obtain the stacktrace as an array. You can pick the original location from there.

Next to that you need to slip into the error message to make this look-alike. Example:

function divide($num1, $num2) {
    if ($num1 == 0 || $num2 == 0) {
        trigger_error_original("Cannot divide by 0", E_USER_ERROR);
    } else {
        return ($num1 / $num2);
    }
}

function trigger_error_original($message, $type) {
    $trace = debug_backtrace(FALSE);
    list($location) = array_slice($trace, 1, 1) + array('file' => 'unknown', 'line' => 'unknown');
    $message .= sprintf(" in %s on line %d\nTriggered", $location['file'], $location['line']);
    trigger_error($message, $type);
}

divide(1, 0);

The error message than shows something like:

> php test-pad.php

Fatal error: Cannot divide by 0 in test-pad.php on line 18
Triggered in test-pad.php on line 15

The downside of this is, that you need to change your code to have this "feature". If you need this for debugging your own code, it's much better that you enable backtraces in your logs. The Xdebug extension does this for you, or you can write your own error handler that takes care of that.

See as well the related question Caller function in PHP 5?. I used array_slice so that you could create an additional parameter to define the number of steps you want to go "up" in the backtrace.

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
0

Use debug_backtrace(), and debug_print_backtrace() for a full call stack. These are especially effective when using Xdebug, which will override the function to colorize the output.

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
0

I have this same problem...

#1: while 10/0 = ERROR, 0/10 = 0 is perfectly legal, you shouldn't have an exception for that.

#2: when you include a file, it effectively becomes part of this new file, so perhaps you might have to toy a little bit with things like __FILE__ and see if you can make it point it to the file before it gets included in the other file..

Felipe
  • 11,557
  • 7
  • 56
  • 103
0

You can use xdebug - it will show you the stacktrace or you can register your own error handndler and display the stacktrace. Just check the example in php.net for set_error_handler().

botzko
  • 630
  • 3
  • 8
0

Maybe exceptions are better to use in your case. You get the full stacktrace and can locate where the function was called without relying on some tricky code :)

pomeh
  • 4,742
  • 4
  • 23
  • 44