PHP
downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

set_exception_handler> <restore_exception_handler
Last updated: Fri, 02 Jan 2009

view this page in

set_error_handler

(PHP 4 >= 4.0.1, PHP 5)

set_error_handlerSets a user-defined error handler function

Description

mixed set_error_handler ( callback $error_handler [, int $error_types ] )

Sets a user function (error_handler ) to handle errors in a script.

This function can be used for defining your own way of handling errors during runtime, for example in applications in which you need to do cleanup of data/files when a critical error happens, or when you need to trigger an error under certain conditions (using trigger_error()).

It is important to remember that the standard PHP error handler is completely bypassed. error_reporting() settings will have no effect and your error handler will be called regardless - however you are still able to read the current value of error_reporting and act appropriately. Of particular note is that this value will be 0 if the statement that caused the error was prepended by the @ error-control operator.

Also note that it is your responsibility to die() if necessary. If the error-handler function returns, script execution will continue with the next statement after the one that caused an error.

The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.

If errors occur before the script is executed (e.g. on file uploads) the custom error handler cannot be called since it is not registered at that time.

Parameters

error_handler

The user function needs to accept two parameters: the error code, and a string describing the error. Then there are three optional parameters that may be supplied: the filename in which the error occurred, the line number in which the error occurred, and the context in which the error occurred (an array that points to the active symbol table at the point the error occurred). The function can be shown as:

handler ( int $errno , string $errstr [, string $errfile [, int $errline [, array $errcontext ]]] )

errno
The first parameter, errno , contains the level of the error raised, as an integer.
errstr
The second parameter, errstr , contains the error message, as a string.
errfile
The third parameter is optional, errfile , which contains the filename that the error was raised in, as a string.
errline
The fourth parameter is optional, errline , which contains the line number the error was raised at, as an integer.
errcontext
The fifth parameter is optional, errcontext , which is an array that points to the active symbol table at the point the error occurred. In other words, errcontext will contain an array of every variable that existed in the scope the error was triggered in. User error handler must not modify error context.

If the function returns FALSE then the normal error handler continues.

error_types

Can be used to mask the triggering of the error_handler function just like the error_reporting ini setting controls which errors are shown. Without this mask set the error_handler will be called for every error regardless to the setting of the error_reporting setting.

Return Values

Returns a string containing the previously defined error handler (if any). If the built-in error handler is used NULL is returned. NULL is also returned in case of an error such as an invalid callback. If the previous error handler was a class method, this function will return an indexed array with the class and the method name.

Changelog

Version Description
5.2.0 The error handler must return FALSE to populate $php_errormsg.
5.0.0 The error_types parameter was introduced.
4.3.0 Instead of a function name, an array containing an object reference and a method name can also be supplied as the error_handler .
4.0.2 Three optional parameters for the error_handler user function was introduced. These are the filename, the line number, and the context.

Examples

Example #1 Error handling with set_error_handler() and trigger_error()

The example below shows the handling of internal exceptions by triggering errors and handling them with a user defined function:

<?php
// error handler function
function myErrorHandler($errno$errstr$errfile$errline)
{
    switch (
$errno) {
    case 
E_USER_ERROR:
        echo 
"<b>My ERROR</b> [$errno$errstr<br />\n";
        echo 
"  Fatal error on line $errline in file $errfile";
        echo 
", PHP " PHP_VERSION " (" PHP_OS ")<br />\n";
        echo 
"Aborting...<br />\n";
        exit(
1);
        break;

    case 
E_USER_WARNING:
        echo 
"<b>My WARNING</b> [$errno$errstr<br />\n";
        break;

    case 
E_USER_NOTICE:
        echo 
"<b>My NOTICE</b> [$errno$errstr<br />\n";
        break;

    default:
        echo 
"Unknown error type: [$errno$errstr<br />\n";
        break;
    }

    
/* Don't execute PHP internal error handler */
    
return true;
}

// function to test the error handling
function scale_by_log($vect$scale)
{
    if (!
is_numeric($scale) || $scale <= 0) {
        
trigger_error("log(x) for x <= 0 is undefined, you used: scale = $scale"E_USER_ERROR);
    }

    if (!
is_array($vect)) {
        
trigger_error("Incorrect input vector, array of values expected"E_USER_WARNING);
        return 
null;
    }

    
$temp = array();
    foreach(
$vect as $pos => $value) {
        if (!
is_numeric($value)) {
            
trigger_error("Value at position $pos is not a number, using 0 (zero)"E_USER_NOTICE);
            
$value 0;
        }
        
$temp[$pos] = log($scale) * $value;
    }

    return 
$temp;
}

// set to the user defined error handler
$old_error_handler set_error_handler("myErrorHandler");

// trigger some errors, first define a mixed array with a non-numeric item
echo "vector a\n";
$a = array(23"foo"5.543.321.11);
print_r($a);

// now generate second array
echo "----\nvector b - a notice (b = log(PI) * a)\n";
/* Value at position $pos is not a number, using 0 (zero) */
$b scale_by_log($aM_PI);
print_r($b);

// this is trouble, we pass a string instead of an array
echo "----\nvector c - a warning\n";
/* Incorrect input vector, array of values expected */
$c scale_by_log("not array"2.3);
var_dump($c); // NULL

// this is a critical error, log of zero or negative number is undefined
echo "----\nvector d - fatal error\n";
/* log(x) for x <= 0 is undefined, you used: scale = $scale" */
$d scale_by_log($a, -2.5);
var_dump($d); // Never reached
?>

The above example will output something similar to:

vector a
Array
(
    [0] => 2
    [1] => 3
    [2] => foo
    [3] => 5.5
    [4] => 43.3
    [5] => 21.11
)
----
vector b - a notice (b = log(PI) * a)
<b>My NOTICE</b> [1024] Value at position 2 is not a number, using 0 (zero)<br />
Array
(
    [0] => 2.2894597716988
    [1] => 3.4341896575482
    [2] => 0
    [3] => 6.2960143721717
    [4] => 49.566804057279
    [5] => 24.165247890281
)
----
vector c - a warning
<b>My WARNING</b> [512] Incorrect input vector, array of values expected<br />
NULL
----
vector d - fatal error
<b>My ERROR</b> [256] log(x) for x <= 0 is undefined, you used: scale = -2.5<br />
  Fatal error on line 35 in file trigger_error.php, PHP 5.2.1 (FreeBSD)<br />
Aborting...<br />



set_exception_handler> <restore_exception_handler
Last updated: Fri, 02 Jan 2009
 
add a note add a note User Contributed Notes
set_error_handler
wfinn at riverbed dot com
09-Jul-2008 06:15
"The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called."

This is not exactly true.  set_error_handler() can't handle them, but ob_start() can handle at least E_ERROR.

<?php

function error_handler($output)
{
   
$error = error_get_last();
   
$output = "";
    foreach (
$error as $info => $string)
       
$output .= "{$info}: {$string}\n";
    return
$output;
}

ob_start('error_handler');

will_this_undefined_function_raise_an_error();

?>
jonbarnett at gmail dot com
11-Apr-2008 07:42
Per the comment below:

There's no problem with static class functions.

The proper way to set a callback for a static class function is:

array("Classname", "functionname")

The class name is a string.  If you don't quote the string, PHP treats it as a barestring and triggers a notice.

/manual/en/language.pseudo-types.php
Alexey Letoshnikov
04-Apr-2008 06:48
There is a problem to set a static function as error handler
<?php
class Debug
{
    public static function
test($num,$err,$file,$line)
    {
        return
true;
    }
}
?>

<?php set_error_handler(array(Debug,'test')); ?>
Static function accepted by set_error_handler() and works but php generates E_NOTICE "Use of undefined constant Debug"

<?php set_error_handler('Debug::test')); ?>
Static function accepted by set_error_handler but does not work

Finaly decided to create a __construct() method and set it as error handler.
<?php set_error_handler(array(new Debug(),'test')); ?>
etienne at perval dot fr
04-Mar-2008 03:17
Note that this function may return NULL in some cases, even when there are no errors.
For instance, this is the case when you call this function for the first time: the function returns NULL simply because there is no previous error handler defined.
m0sh3 at hotmail dot com
05-Feb-2008 09:33
Looks like there's no way to distinguish between catched exceptions thrown by internal classes and real warnings in custom error handlers:

<?php
function handleError($n, $m, $f, $l) {
   
//no difference between excpetions and E_WARNING
   
echo "user error handler: e_warning=".E_WARNING."  num=".$n." msg=".$m." line=".$l."\n";
    return
true;
   
//change to return false to make the "catch" block execute;
}
set_error_handler('handleError');
//turn off to make try/catch work normally

//uncomment this for a regular warning
timezone_open(1202229163);

//comment this whole try/catch out to see new DateTimeZone outside of a try / catch
//behavior is the same if you have set a custom error handler

//echo new DateTimeZone(1202229163);

//*
try {
   
$z = new DateTimeZone(1202229163);
} catch (
Exception $e) {
    echo
"caught";
}
// */
?>
webmaster at paramiliar dot com
03-Jan-2008 11:03
We needed to use an error handler to handle SQL errors while passing the query along so the query is also logged and this is what we came up with, its kind of an ugly bridge but it works 100%

<?php

function myErrorHandler($errno, $errstr, $errfile, $errline){
    switch (
$errno) {
    case
E_USER_ERROR:
        if (
$errstr == "(SQL)"){
           
// handling an sql error
           
echo "<b>SQL Error</b> [$errno] " . SQLMESSAGE . "<br />\n";
            echo
"Query : " . SQLQUERY . "<br />\n";
            echo
"On line " . SQLERRORLINE . " in file " . SQLERRORFILE . " ";
            echo
", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
            echo
"Aborting...<br />\n";
        } else {
            echo
"<b>My ERROR</b> [$errno] $errstr<br />\n";
            echo
"  Fatal error on line $errline in file $errfile";
            echo
", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
            echo
"Aborting...<br />\n";
        }
        exit(
1);
        break;

    case
E_USER_WARNING:
    case
E_USER_NOTICE:
    }
   
/* Don't execute PHP internal error handler */
   
return true;
}

// function to test the error handling

function sqlerrorhandler($ERROR, $QUERY, $PHPFILE, $LINE){
   
define("SQLQUERY", $QUERY);
   
define("SQLMESSAGE", $ERROR);
   
define("SQLERRORLINE", $LINE);
   
define("SQLERRORFILE", $PHPFILE);
   
trigger_error("(SQL)", E_USER_ERROR);
}

set_error_handler("myErrorHandler");

// trigger an sql error
$query = "SELECT * FROM tbl LIMIT 1";
$sql = @mysql_query($query)
    or
sqlerrorhandler("(".mysql_errno().") ".mysql_error(), $query, $_SERVER['PHP_SELF'], __LINE__);
   

?>
michal dot kocarek at NO_SPAM dot seznam dot cz
23-Sep-2007 02:55
Be aware of efficiency and speed of your scripts!

If you use old-fashioned non-strict variable calling (example follows...), your custom error handler function degrades the script speed very big (especially for bigger projects). Because of for every "use of undefined constant" or "undefined variable" E_NOTICEs will be called your own custom error handler function.

<?
if ($form_variable) { ///< E_NOTICE Undefined variable
   // process form stuff
}
$foo[bar] = $const_array[baz]; ///< 2x E_NOTICE Use of undefined constant bar, baz

if (!$d) { // declare default $d ///< E_NOTICE Undefined variable
   $d = 5;
}
?>

As you can see in this poor example, badly writted scripts decrease the performace very big 'cause of the error handler is called almost everytime. So use custom-error-handler on heavily used pages only if you are writing scripts strictly. (Example follows:)
<?
if (isset($form_variable) && $form_variable != null) {
   // process form stuff
}
$foo['bar'] = $const_array['baz'];

if (!isset($d) || $d == null) {
   $d = 5;
}
?>
ash
04-Aug-2007 03:38
error handling function that handles both errors and exceptions; also features a backtrace including possible function arguments.

<?php

$cfg
= array();
$cfg['debug'] = 1;
$cfg['adminEmail'] = 'name@domain.tld';

function
errorHandler($errno, $errstr='', $errfile='', $errline='')
{
   
// if error has been supressed with an @
   
if (error_reporting() == 0) {
        return;
    }

    global
$cfg;

   
// check if function has been called by an exception
   
if(func_num_args() == 5) {
       
// called by trigger_error()
       
$exception = null;
        list(
$errno, $errstr, $errfile, $errline) = func_get_args();

       
$backtrace = array_reverse(debug_backtrace());

    }else {
       
// caught exception
       
$exc = func_get_arg(0);
       
$errno = $exc->getCode();
       
$errstr = $exc->getMessage();
       
$errfile = $exc->getFile();
       
$errline = $exc->getLine();

       
$backtrace = $exc->getTrace();
    }

   
$errorType = array (
              
E_ERROR            => 'ERROR',
              
E_WARNING        => 'WARNING',
              
E_PARSE          => 'PARSING ERROR',
              
E_NOTICE         => 'NOTICE',
              
E_CORE_ERROR     => 'CORE ERROR',
              
E_CORE_WARNING   => 'CORE WARNING',
              
E_COMPILE_ERROR  => 'COMPILE ERROR',
              
E_COMPILE_WARNING => 'COMPILE WARNING',
              
E_USER_ERROR     => 'USER ERROR',
              
E_USER_WARNING   => 'USER WARNING',
              
E_USER_NOTICE    => 'USER NOTICE',
              
E_STRICT         => 'STRICT NOTICE',
              
E_RECOVERABLE_ERROR  => 'RECOVERABLE ERROR'
              
);

   
// create error message
   
if (array_key_exists($errno, $errorType)) {
       
$err = $errorType[$errno];
    } else {
       
$err = 'CAUGHT EXCEPTION';
    }

   
$errMsg = "$err: $errstr in $errfile on line $errline";

   
// start backtrace
   
foreach ($backtrace as $v) {

        if (isset(
$v['class'])) {

           
$trace = 'in class '.$v['class'].'::'.$v['function'].'(';

            if (isset(
$v['args'])) {
               
$separator = '';

                foreach(
$v['args'] as $arg ) {
                   
$trace .= "$separator".getArgument($arg);
                   
$separator = ', ';
                }
            }
           
$trace .= ')';
        }

        elseif (isset(
$v['function']) && empty($trace)) {
           
$trace = 'in function '.$v['function'].'(';
            if (!empty(
$v['args'])) {

               
$separator = '';

                foreach(
$v['args'] as $arg ) {
                   
$trace .= "$separator".getArgument($arg);
                   
$separator = ', ';
                }
            }
           
$trace .= ')';
        }
    }

   
// display error msg, if debug is enabled
   
if($cfg['debug'] == 1) {
        echo
'<h2>Debug Msg</h2>'.nl2br($errMsg).'<br />
            Trace: '
.nl2br($trace).'<br />';
    }

   
// what to do
   
switch ($errno) {
        case
E_NOTICE:
        case
E_USER_NOTICE:
            return;
            break;

        default:
            if(
$cfg['debug'] == 0){
               
// send email to admin
               
if(!empty($cfg['adminEmail'])) {
                    @
mail($cfg['adminEmail'],'critical error on '.$_SERVER['HTTP_HOST'], $errorText,
                           
'From: Error Handler');
                }
               
// end and display error msg
               
exit(displayClientMessage());
            }
            else
                exit(
'<p>aborting.</p>');
            break;

    }

}
// end of errorHandler()

function displayClientMessage()
{
    echo
'some html page with error message';

}

function
getArgument($arg)
{
    switch (
strtolower(gettype($arg))) {

        case
'string':
            return(
'"'.str_replace( array("\n"), array(''), $arg ).'"' );

        case
'boolean':
            return (bool)
$arg;

        case
'object':
            return
'object('.get_class($arg).')';

        case
'array':
           
$ret = 'array(';
           
$separtor = '';

            foreach (
$arg as $k => $v) {
               
$ret .= $separtor.getArgument($k).' => '.getArgument($v);
               
$separtor = ', ';
            }
           
$ret .= ')';

            return
$ret;

        case
'resource':
            return
'resource('.get_resource_type($arg).')';

        default:
            return
var_export($arg, true);
    }
}

?>
Thomas
18-Jul-2007 01:57
Be careful with error-handlers if you are using require() with a function as argument, like
<?php
 
require(foo($foo));
?>
If the result of the function isn't a valid file to be included, you wont get any errormessage, but your script will crash without any output (see the bug-database for further details: http://bugs.php.net/bug.php?id=41862).
stepheneliotdewey at GmailDotCom
26-Jun-2007 09:26
Additional note based on some further testing:

Although errcontext is effectively an array passed by reference to your custom error handling function, you cannot simply copy it over to another variable, because that variable will also act like a reference to errcontext, almost like an object.

Instead, the only way I can find to copy the errcontext array to a separate variable so that you can actually modify its values without changing the surrounding variable context, is to copy it piece-by-piece with a foreach loop. Not the most efficient way of working, but then again, errors are hopefully exceptional enough for you that performance will not be an overriding concern in this case.
stepheneliotdewey at GmailDotCom
26-Jun-2007 08:48
The manual states:

"errcontext will contain an array of every variable that existed in the scope the error was triggered in. User error handler must not modify error context."

But do you know WHY you must not modify the error context? It appears that errcontext is (in effect if not literally) created by taking $GLOBALS and adding the non-global local variables as additional entries in that array, then passing the whole thing *by reference*.

(You can prove this to be true if you set up a custom error handler and then print_r($errcontext) within it, because $GLOBALS will be printed as a recursive array).

In other words, the language in the manual is misleading, because errcontext is NOT a copy of the variables that existed when the error WAS triggered, but rather is a reference to the *existing LIVE variables* in the calling script.

This includes superglobal variables like $_SERVER, $_POST, $_GET, etc., as well as all user-defined variables in scope.

The significance of that is that if you modify errcontext, you will be modifying those other variables, not just for the life of your error handling function, but for the life of the calling script as well.

That doesn't matter if you plan to halt execution in your error handling function, but it will lead to unexpected behavior if you modify $errcontext and then return to the program's normal flow after handling the error, because the variables will stay modified. For example, if you unset $_SERVER in your custom error handling function, it will remain unset once the function is over and you have returned to the page that generated the error.

This should be made clearer in the manual, starting by marking errhandler with an ampersand (&) for passage by reference in the "Parameters" section above, like so:

handler ( int $errno, string $errstr [, string $errfile [, int $errline [, array &$errcontext]]] )
gotrunko at hotmail dot com
20-Jun-2007 01:26
To ereg error in a text file

<?php
$log_file
="log.txt";

set_error_handler(log_handler);

function
log_handler ( $errno, $errstr$errfile, $errline, $errcontext )
{
   
$context = var_export($errcontext, TRUE);
   
log_error_ereg("errno:$errno ($errstr) file:$errfile, line:$errline, context:$context\n");
}

function
log_error_ereg($mess)
{
    global
$log_file;

   
$fd = fopen($log_file, 'a');
    if(!
$fd)
    {
        echo
"<pre>$mess</pre>";
    }
    else
    {
        if(!
fwrite($fd, date('Y-m-d H:i:s')." ERR : \n$mess\n\n"))
        {
            echo
"<pre>$mess</pre>";
        }
       
fclose($fd);
    }
}
?>
greg sidberry[poetics5 at yahoo dot com]
15-May-2007 10:32
I was using a class, and needed to have a function within it handle php errors.

The following code will allow you to call a class function of already defined object while maintaining access to all the objects current data .
============================

set_error_handler("classPassPHPError");

$ObjectName="test";

$test->new className;

function classPassPHPError($errno, $errstr, $errfile, $errline){
global $ObjectName;

eval("global \$".$ObjectName.";");
eval("\$object=\$".$ObjectName.";");

$object->phpErrorHandler($errno, $errstr, $errfile, $errline);
$object=null;
}
silkensedai at online dot fr
02-May-2007 12:37
i made an error handler that print also the backtrace and that can die on some errors. It can be useful if you want to die on every error you find.

<?php

function my_error_handler($errno, $errstr, $errfile, $errline){
   
$errno = $errno & error_reporting();
    if(
$errno == 0) return;
    if(!
defined('E_STRICT'))            define('E_STRICT', 2048);
    if(!
defined('E_RECOVERABLE_ERROR')) define('E_RECOVERABLE_ERROR', 4096);
    print
"<pre>\n<b>";
    switch(
$errno){
        case
E_ERROR:               print "Error";                  break;
        case
E_WARNING:             print "Warning";                break;
        case
E_PARSE:               print "Parse Error";            break;
        case
E_NOTICE:              print "Notice";                 break;
        case
E_CORE_ERROR:          print "Core Error";             break;
        case
E_CORE_WARNING:        print "Core Warning";           break;
        case
E_COMPILE_ERROR:       print "Compile Error";          break;
        case
E_COMPILE_WARNING:     print "Compile Warning";        break;
        case
E_USER_ERROR:          print "User Error";             break;
        case
E_USER_WARNING:        print "User Warning";           break;
        case
E_USER_NOTICE:         print "User Notice";            break;
        case
E_STRICT:              print "Strict Notice";          break;
        case
E_RECOVERABLE_ERROR:   print "Recoverable Error";      break;
        default:                    print
"Unknown error ($errno)"; break;
    }
    print
":</b> <i>$errstr</i> in <b>$errfile</b> on line <b>$errline</b>\n";
    if(
function_exists('debug_backtrace')){
       
//print "backtrace:\n";
       
$backtrace = debug_backtrace();
       
array_shift($backtrace);
        foreach(
$backtrace as $i=>$l){
            print
"[$i] in function <b>{$l['class']}{$l['type']}{$l['function']}</b>";
            if(
$l['file']) print " in <b>{$l['file']}</b>";
            if(
$l['line']) print " on line <b>{$l['line']}</b>";
            print
"\n";
        }
    }
    print
"\n</pre>";
    if(isset(
$GLOBALS['error_fatal'])){
        if(
$GLOBALS['error_fatal'] & $errno) die('fatal');
    }
}

function
error_fatal($mask = NULL){
    if(!
is_null($mask)){
       
$GLOBALS['error_fatal'] = $mask;
    }elseif(!isset(
$GLOBALS['die_on'])){
       
$GLOBALS['error_fatal'] = 0;
    }
    return
$GLOBALS['error_fatal'];
}

?>

Usage :

<?php
error_reporting
(E_ALL);      // will report all errors
set_error_handler('my_error_handler');
error_fatal(E_ALL^E_NOTICE); // will die on any error except E_NOTICE
?>
elven_rangers at yahoo dot com
14-Feb-2007 04:22
Unfortunately, none of the procedures described here by other users to catch all errors work.

Then again this would be impossible as parse errors are triggered before the code is interpreted and executed so no code solution is possible (just as the documentation says).

You can test them easily against this simple code:

some_function_that_doesnt_exist();

using it in this form will trigger a Fatal Error (call to undefined function), which can't be caught by using your custom defined handler but *can* be caught by using the solutions presented by other programmers.

if you remove the ; from the end will trigger a Parse Error (syntax error), which *can't* be caught by any of these solutions. If this called is however places as the last line of code, just before the ?> then it will again generate a Fatal Error (call to undefined function).

if you further remove the () then you'll get a Notice (undefined constant) which can be caught by the manual method of defining a custom error handler.
mail at chernousov dot com
24-Oct-2006 03:52
When fatal error occurs, class destructors are not executed.

<?

class someClass {
  function __construct() {
    echo '__construct()';
  }

  function __destruct() {
    echo '__destruct()';
  }
}

$someClass = new someClass();
someNonExistentFunction();

?>

Result will be:

__construct()
Fatal error: Call to undefined function someNonExistentFunction() in tes.php on line 14
alexey.kupershtokh.gmail
02-Oct-2006 12:07
2errd
I've got more convenient and safe error to exception converter:

class CustomException extends Exception {
  public static function errorHandlerCallback($code, $string, $file, $line, $context) {
    $e = new self($string, $code);
    $e->line = $line;
    $e->file = $file;
    throw $e;
  }
}
set_error_handler(array("CustomException", "errorHandlerCallback"), E_ALL);
dk at brightbyte dot de
27-Aug-2006 04:09
Sometimes, you want to "catch" only some errors, and let the default handler deal with the result. I just found out that (at least in PHP 5), the default handler will be called if you return false (not 0 or NULL or '', but false) from your custom handler. This allows for "chaining" handlers.

The fature was suggested in this thread:
http://www.zend.com/lists/php-dev/200405/msg00491.html - the initial suggestion was to call the default handler if true is returned, but this was changed later on, apperently.
jla
27-Jul-2006 04:16
Other option to "handle" ALL errors

set_error_handler("yourHandler");

// Parse,Compile, Core, etc... Errors
ini_set('html_errors',false);
ini_set('error_prepend_string','<html><head><META http-equiv="refresh" content="0;URL=/error.php?msg=');
ini_set('error_append_string','"></head></html>');
kariedoo
08-May-2006 01:07
function errorlog($type, $info, $file, $row)
{
   if ($handle = fopen("./log/ftp_error.log", "a"))
   {
      @fwrite($handle, date("Y-m-d H:i:s")." "--> $type: $info FILE: $file -  Row $row\r\n" );
      @fclose($handle);
   }//end if
}//end function

### in the error logging code for example ftp: ###

set_error_handler("errorlog");  //set your own Handler
 
$this->connect = ftp_connect(TXTCONNECT);
$this->login = ftp_login($this->connect, TXTID, FTPPASS);
$this->systype= ftp_systype($this->connect);

restore_error_handler(); //restore the old handler

------------------
content in file
------------------

2006-05-08 09:36:02 2: ftp_login(): Login incorrect. FILE: /html/cgi-bin/test/classes/ftp.class.php - Row 63
docey
05-Apr-2006 12:50
if you wan't to know the current error-handler
set use something like this:

$current_errorhandler = set_error_handler("myerrorhandler");
restore_error_handler();

this will set your custom error_handler and return
the name of the previous set error handler. by
calling restore_error_handler, you remove your
custom error_handler and set the error_handler that
was set back again.

this way you can also switch back to php-default error-handler
without knowing how many error-handler already
are set, by using a loop till an empty string is
returned. because an empty string means
"no error-handler set" wich means php's default
errorhandler is set back.

like in this code below:

function restore_phperrorhandler()
{
 // get current error handler.
 $previous_errorhandler =
 set_error_handler("myerrorhandler");
 restore_error_handler();

 $max_loops = 20;
 $cur_loops = 0;
    
 // if current error handler is not already php's or fails.
    if(($previous_errorhandler != NULL) OR
      ($previous_errorhandler != "")){
   
        while($previous_errorhandler != ""){
         $cur_loops = $cur_loops + 1;
            
            // check if not exceeding infinit loop.
            if($cur_loops >= $max_loops){
              trigger_error("Restoring exceeds max. loops.",
              E_USER_WARNING);
             return false;
            }
        
            //switch to previous handler.
            restore_error_handler();
        
            // get its name and switch to it again.
            $previous_errorhandler =
            set_error_handler("myerrorhandler");
            restore_error_handler();
        
           // check if getting errorhandler failed.
           if($previous_errorhandler == NULL){
              trigger_error("Failed to get prev. error handler",
              E_USER_WARNING);
            return false;
            
            // empty string = php-default error handler
            }elseif($previous_errorhandler == ""){
             return true;
            }
        }
    }else{
      trigger_error("Current Error-Handler is default.",
      E_USER_NOTICE);
     return true;
    }
}

this function will loop and return true when no
error handler is left. leaving php-default handler
in controll again. this is usefull if you want to
disable your own error-handler but be sure that
php's is handling your error's and not any other
error-handler.
errd
30-Jan-2006 05:52
In errors to exceptions conversion below I found some incorrect stuff. File and line properties of Exception point to line and file where Exception is thrown, but not where real error is occured.

Impoved errors to exceptions converting:
+ Fixed filename of exception handled
+ Fixed code line of exception handled

<?php

class CustomException extends Exception {
    public function
setLine($line) { 
       
$this->line=$line;
    }
    
    public function
setFile($file) {
       
$this->file=$file;
    }
}

function
exceptionsHandler($code, $string, $file, $line) { 
   
$exception=new CustomException($string, $code);
   
$exception->setLine($line);
   
$exception->setFile($file);
    throw
$exception;


set_error_handler('exceptionsHandler', E_ALL);

?>
24-Jan-2006 01:19
To honor the value of PHP's error_reporting() function, use:

<?
  if( ($level & error_reporting()) == 0 ) return;
?>
Gulopine
05-Jan-2006 09:36
Also note that even though the documentation states "errcontext will contain an array of every variable that existed in the scope the error was triggered in," that is not the case for $this in an instantiated object, as of PHP 5.1.1.

<?php

function error_function($errno, $errstr, $errfile, $errline, $errcontext) {
   
print_r($errcontext);
}

set_error_handler('error_function');

class
test_class {
    private
$id;
   
    function
__construct($id) {
       
$this->id = $id;
       
trigger_error('Test error');
    }
}

$test = new test_class(5);

?>

Result:

Array
(
    [id] => 5
)

I discovered this when trying to write an error handler that would log the class the error occured in, as it was triggered from a function in a parent class extended by several individual classes.
ia [AT] zoznam [DOT] sk
22-Sep-2005 04:33
as reply to dawiddr at gmail dot com:

Be careful with this when using __autoload(). When there is some error during parsing the file included in __autoload() so an exception is thrown, it results in following error:

Fatal error:  Function __autoload(ClassName) threw an exception of type 'Exception' in /network/webroot/dev/test.php on line 121

It is because exceptions can't be thrown in __autoload().
See __autoload() documentation (http://www.php.net/autoload) and bug #31102 (http://bugs.php.net/bug.php?id=31102&edit=3)
florian at siweho dot de
22-Aug-2005 12:26
@ mmtache at yahoo dot com
you have to use
if(error_reporting() != 0){
   .... (yourOwnHandler)

instead of
if(error_reporting()){
   ....

in PHP5. then operations like this "@fopen" won't show an error-message
eregon at eregon dot info
02-Aug-2005 09:35
It is not possible to handle fatal errors with own handler. Even if you have set your own handler, fatal error will be always handled by PHP's default handler. The reason is the script may be in unstable state after fatal error occurence (details here: http://marc.theaimsgroup.com/?l=php-dev&m=97673386418430&w=2).
dawiddr at gmail dot com
05-Jul-2005 04:01
In PHP5, if you want to have exceptions thrown instead of normal errors - you could use an error handler, which throw exceptions:

<?php

function handler($errno, $errstr, $errfile, $errline)
{
    print
"Error handled!\n";
    throw new
Exception($errstr, $errno);
}

set_error_handler('handler');

try
{
    print
2 / 0; // simple error - division by zero
   
print "This will never be printed";
}
catch (
Exception $e)
{
    print
"Exception catched:\n";
    print
"Code: ".$e->getCode()."\n";
    print
"Message: ".$e->getMessage()."\n";
    print
"Line: ".$e->getLine();
}

?>

Result:

Error handled!
Exception catched:
Code: 2
Message: Division by zero
Line: 6

As you see, exception is catched like it have been thrown by division by zero - in try/catch clause. But line numer and backtrace shows, that is was thrown by the error handler.
frank at ethisoft dot nl
01-Jun-2005 03:11
Perhaps it is worth mentioning that in
PHP5
both set_error_handler & set_exception_handler can be called with an array containing 2 arguments:
1) var  ==> object
2) string ==> name of handler function in object

EXAMPLE:
<?php
set_error_handler              
(array($object, 'handler_function'));
set_exception_handler      (array($object, 'handler_function'));
?>

Both can point to the same object and handler_function so that both error and exception handling, which are very much alike usually, can be done by only 1 dedicated class.
jgiglio at netmar dot com
25-Mar-2005 08:02
set_error_handler also overrides the default behavior of postgresql which is to shoot HTML errors to the browser on a query failure or other database error.

I can't find a list of symbolic $errno names for postgres errors, but a normal "bad query" throws an errno of 2.

Be careful to not use an empty default case in your errno case statement if you use postgresql, and expect php to generate DB errors automatically.
Steffen Staehle
12-Jan-2005 02:29
Two notes on using set_error_handler() on behaviour that I noticed when migrating an application from php 4.2.1 to php 4.3.9 (I do not yet have php 5.0 available, this might not apply there!).

1. setting the system error handler

If you want to set the standard php error handler again, after having set your own error handler, this works in php 4.2.1 by passing in an empty string:

<?php

  
function my_handler($log_level, $log_text, $error_file, $error_line)
   {
     
// if an error occurs here, the standard error
      // would be called (to avoid recursion)

      // do something useful
      // ...
  
}

  
$last_handler = set_error_handler("my_handler");

  
// after this, $last_handler == ""

   // restore standard error handler

  
$last_handler = set_error_handler("");

  
// after this, $last_handler == "my_handler"

?>

The very same code now raises an error in php 4.3.9:

   set_error_handler() expects argument 1, '', to be a valid callback

(Since the return value of the first call to set_error_handler() is still the empty string "", I don't see how this can be done any more. I don't really need this, because I use my own handlers as shown below, but it might be good to be aware of this.)

2. setting your own 'second level' handler

If you have set your own error handler, and want to replace it by another one (other than the standard php error handler) while it is being executed, note that the return value of set_error_handler when used INSIDE the error handler is "" instead of the name of the previous handler! This is not too surprising, because during execution of your self defined error handler, php replaces it with the standard php error handler to avoid infinite loops in case of problems inside the handler. This is only interesting if you want nested handlers as I do. Background of my design:

   1st level handler: log into DB
   2nd level handler: log into flat file (if log into DB fails)
   3rd level handler: print to stdout (if log into flat file fails) (this is the sytem handler, finally).

<?php

  
function my_fallback_handler($log_level, $log_text, $error_file, $error_line)
   {
     
// if an error occurs here, the standard error
      // would be called (to avoid recursion)

      // do something useful
      // ...

  
} // my_fallback_handler

  
function my_handler($log_level, $log_text, $error_file, $error_line)
   {
     
// if an error occurs here, the standard error
      // would be called (to avoid recursion)

      // but we want to have a fallback handler different
      // to the standard error handler

     
$last_handler = set_error_handler("my_fallback_handler");

     
// I expected $last_handler == "my_handler"
      // (which it would outside my_handler())
      // but here it is the empty string ""

      // do something useful
      // ...

      // now set the 1st level handler again:
      // (do NOT use $last_handler as argument,
      // because it equals "")

     
$last_handler = set_error_handler("my_handler");

   }
// my_handler

  
$last_handler = set_error_handler("my_handler");

?>
Sukender
10-Aug-2004 08:29
In PHP5, ou can ask for the default handler to be called after your custom handler by returning "false". See this pseudo-code :
<?
function MyHandler($errno, $errstr, $errfile, $errline, $errcontext) {
    my_handling_code;        // Do something, such as sending an email to the admin
    if (i_want_to_call_the_default_handler) return false;        // will invoke the default error handler just after
    else return true;        // This will NOT invoke it (= you've properly handled the error)
}
set_error_handler("MyHandler");
?>

I have not tested the functionality, but I think that the php.ini directive "log_errors" keeps working, but *only* when you call the default handler (= retrun false).

>>> Source : Mailing list thread about "re-invoking default error handler" at http://www.zend.com/lists/php-dev/200405/msg00491.html (be careful about the first post : "true" and "false" are switched - because it's only a proposition).
Joe
29-Jun-2004 10:26
When a custom error handler is set, the php.ini directive "log_errors" stops working.  I'm guessing to favor your custom handler.  You can still log your errors with the "error_log" function, but it doesn't happen when you have a custom error handler.
Cezary Tomczak
22-Apr-2004 01:25
Here is a script to debug / display errors in a nice way: http://gosu.pl/demo/ErrorHandler/ErrorHandler.zip

Example of displaying an error: http://gosu.pl/demo/ErrorHandler/example1.html
Example of displaying source of the file where the error appeared: http://gosu.pl/demo/ErrorHandler/example2.html

Displaying error: generates a backtrace, show file / line, show function / arguments (and values), source of the file
erwin at isiz dot nl
19-Apr-2004 06:51
@sijmen at digitized dot nl
That's not true. The reference operator does have effect, when used correctly.

Your code doesn't use the reference operator in the set_error_handler function, but it does when creating the new error object. In your case, you have to use the reference operator two times.

When calling the set_error_handler function

<?php
        set_error_handler
(array(&$this, 'handler'));
?>

and when creating the class

<?php
$eh
= &new error;
?>

In that case the same error class will be used and the output will be following:
Error!
!!

Hope this helps.
mightye (at) mightye (dot) org
12-Apr-2004 02:18
You can't use this functionality to catch parse errors in included, required, or eval()'d code.  Parse errors seem to exist on a deeper level.
sijmen at digitized dot nl
09-Apr-2004 07:47
@jayp at groovejob dot com
As I said before, the reference operator doesn't have any effect on the the error handler.

Proof of concepts:
http://trouby.digitized.nl/set_error_handler2.php
http://trouby.digitized.nl/set_error_handler2.php?source=1
jayp at groovejob dot com
03-Apr-2004 09:28
In response to sijmen at digitized dot nl:

Instead of

$eh = new error;

use

$eh =& new error();

The new operator returns a copy of the error object, so the error handler that is set in the constructor is tied to a different object instance than the instance returned by "new".  To make sure you are working with the exact same object instance that you think you are, it's best to use the reference object when creating instances of objects, like so:

$oMyObject =& new MyObject();

HTH,

Jay
sijmen at digitized dot nl
30-Mar-2004 07:23
@skyrl at free dot fr
It seems that the reference operator '&' doesn't have any effect. That's why I submitted the comment.

<?php
class error {
    var
$error;

    function
error() {
       
$this->setIni();
    }

    function
handler() {
        echo
$this->error.'!!';
    }

    function
setText($text) {
        
$this->error = $text;
    }

    function
setIni() {
       
set_error_handler(array(&$this