7

odbc_errormsg does not report error messages from odbc_execute the way it's supposed to. It merely throws a warning. So I've been forced to write a hack to parse the error message via error_get_last.

I'm using set_error_handler and error_get_last returns NULL unless I either:

  1. disable my error handler,

  2. or make it return FALSE.

I'd suppose this is due to PHP's builtin error handler taking care of storing the error details somewhere so they can be retrieved later.

Is there a way to emulate such behaviour in my custom error handler so error_get_last() can be used normally?

Please note I already know several ways to retrieve error info at any time. My question is how to make error_get_last usable.


Update: I think I'd better post some code.

PHP has error_get_last(), which allows to do this:

@fopen('xxx');
var_dump( error_get_last() );

... and get this:

array(4) {
  ["type"]=>
  int(2)
  ["message"]=>
  string(46) "fopen() expects at least 2 parameters, 1 given"
  ["file"]=>
  string(69) "C:\Documents and Settings\ALVARO.GONZALEZ\Mis documentos\tmp\test.php"
  ["line"]=>
  int(3)
}

This breaks if you replace the builtin error handler:

function custom_error_handler($errno, $errstr, $errfile, $errline){
    $ignore = ($errno & error_reporting()) == 0;
    if(!$ignore){
        echo "[Error happened: $errstr]\n";
    }
    return TRUE;
}
set_error_handler('custom_error_handler');

@fopen('xxx');
var_dump( error_get_last() ); // NULL

If you keep both error handlers...

function custom_error_handler($errno, $errstr, $errfile, $errline){
    $ignore = ($errno & error_reporting()) == 0;
    if(!$ignore){
        echo "[Error happened: $errstr]\n";
    }
    return FALSE;
}
set_error_handler('custom_error_handler');

error_reporting(E_ALL);
echo $foo;

... you get side effects:

[Error happened: Undefined variable: foo]

Notice: Undefined variable: foo in C:\Documents and Settings\ALVARO.GONZALEZ\Mis documentos\tmp\test.php on line 15

Call Stack:
    0.0004     329720   1. {main}() C:\Documents and Settings\ALVARO.GONZALEZ\Mis documentos\tmp\test.php:0

... instead of just:

[Error happened: Undefined variable: foo]

I want to my custom error handler to interface properly with error_get_last. I want error_get_last to work fine.

Pacerier
  • 86,231
  • 106
  • 366
  • 634
Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • Would you accept using a different (user-defined) function? Because if you would, you could just store the last error in a global var, and have a function that just does `return $GLOBALS['varname'];` – DaveRandom Dec 14 '11 at 12:17
  • Is returning `false` not acceptable? If so, why? – Jon Dec 14 '11 at 12:20
  • Also, have you tried assigning a value to [`$php_errormsg`](http://uk.php.net/manual/en/reserved.variables.phperrormsg.php)? I have no idea if this would achieve (or even affect) anything, but it might be worth a try... – DaveRandom Dec 14 '11 at 12:20
  • @Jon - Because it executes both error handlers: first mine, then PHP's. Mine is a replacement, not a complement. – Álvaro González Dec 14 '11 at 12:23
  • 1
    @ÁlvaroG.Vicario: I understand that. My question could be also phrased as "what problem does PHP's error handler cause if you let it execute?". – Jon Dec 14 '11 at 12:25
  • @DaveRandom - I know there're many ways to replace `error_get_last()`. I just want to write a custom error handler that doesn't break other functionality. /// Setting `$php_errormsg` doesn't prevent `error_get_last()` from returning NULL (just tested it). – Álvaro González Dec 14 '11 at 12:28
  • @Jon - The most obvious is a second error message on screen. – Álvaro González Dec 14 '11 at 12:30
  • @ÁlvaroG.Vicario: I 'm asking because I am considering possible hacks. Did you try simply reimplementing the functionality of `error_get_last` from within your own handler (i.e. saving to some variable and fetching it later)? At first sight it seems to be the cleanest possible solution. – Jon Dec 14 '11 at 12:48
  • @Jon - Unlike JavaScript, PHP does not allow to redefine functions. I can write my own function but it cannot call it `error_get_last()`. – Álvaro González Dec 14 '11 at 12:54
  • @ÁlvaroG.Vicario: I imagine the name of the function to call is not part of your requirements, right? – Jon Dec 14 '11 at 12:58

2 Answers2

6

Right, this is a bizarre solution, but I think it will suit your purposes.

After a bit of playing around, I have discovered that this:

function my_error_handler ($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array()) {

  // Handle the error here

  @trigger_error($errstr);
  return TRUE;

}

// Just to make sure PHP is not outputting anything
error_reporting(-1);
ini_set('display_errors',1);

set_error_handler('my_error_handler');

// An E_USR error...
trigger_error('Some error');
var_dump(error_get_last());

// ...and a native one
$key = count();
var_dump(error_get_last());

Results in this:

array(4) {
  ["type"]=>
  int(1024)
  ["message"]=>
  string(10) "Some error"
  ["file"]=>
  string(69) "C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test.php"
  ["line"]=>
  int(7)
}
array(4) {
  ["type"]=>
  int(1024)
  ["message"]=>
  string(45) "count() expects at least 1 parameter, 0 given"
  ["file"]=>
  string(69) "C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test.php"
  ["line"]=>
  int(7)
}

Calling @trigger_error() from within your error handler, and not returning FALSE, causes error_get_last() to return something other than NULL, but because the error is suppressed with @, PHP doesn't output anything. It seems that in the interests of avoiding an infinite recursion, calling trigger_error() from within the registered error handler function does not call the error handler - which works to our advantage here.

Obviously, the error code has been modified, but you could convert it to the relevant E_USR_* code if you need - but I suspect what you really want is the string value, which this method will allow you get. You have, unfortunately, also lost the line number and file information - although you could possibly get this back by doing something involving a stack trace inside the error handler, or at the very least including it in the string from the arguments passed.

This is a horrible, horrible, horrible hack - but since there is no officially sanctioned way to do this, a hack is essentially what you are asking for.

DaveRandom
  • 87,921
  • 11
  • 154
  • 174
0

You could change your custom error handler to return false, just when the error is ignored (@-operator used).

function custom_error_handler($errno, $errstr, $errfile, $errline){
    $ignore = ($errno & error_reporting()) == 0;
    if ($ignore) {
        return FALSE;
    }
    echo "[Error happened: $errstr]\n";
    return TRUE;
}
Doctorj
  • 24
  • 2