PHP 5.6.0 released

set_error_handler

(PHP 4 >= 4.0.1, PHP 5)

set_error_handlerSpécifie une fonction utilisateur comme gestionnaire d'erreurs

Description

mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )

set_error_handler() choisit la fonction utilisateur error_handler pour gérer les erreurs dans un script.

set_error_handler() peut être utilisé pour définir votre propre manière de gérer les erreurs durant l'exécution, par exemple pour une application dans laquelle vous devez nettoyer les données/fichiers lorsqu'une erreur survient ou lorsque vous devez déclencher une erreur sous certaines conditions (en utilisant trigger_error()).

Il faut se rappeler que la fonction standard de traitement des erreurs de PHP est alors complètement ignorée pour les erreurs de types spécifiés par error_types à moins que la fonction de rappel retourne FALSE. error_reporting() n'aura plus d'effet, et votre fonction de gestion des erreurs sera toujours appelée. Vous pourrez toujours lire la valeur de l'erreur courante de error_reporting et faire réagir la fonction de gestion des erreurs en fonction. Cette remarque est notamment valable si la commande a été préfixée par @.

Notez aussi qu'il est alors confié à cette fonction de terminer le script (die()) si nécessaire. Si la fonction de gestion des erreurs se termine normalement, l'exécution du script se poursuivra avec l'exécution de la prochaine commande.

Les types d'erreur suivants ne peuvent pas être gérés avec cette fonction : E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING ainsi que la plupart des E_STRICT du fichier dans lequel set_error_handler() est appelé.

Si une erreur survient avant que le script ne soit exécuté (par exemple un téléchargement de fichier), le gestionnaire d'erreurs personnalisé ne pourra pas être appelé, car il n'est pas encore enregistré.

Liste de paramètres

error_handler

Une fonction de rappel avec la signature suivante. NULL peut être passé à la place, pour ré-initialiser ce gestionnaire en son statut par défaut. Au lieu d'un nom de fonction, un tableau contenant une référence d'objet et un nom de méthode peut également être fourni.

bool handler ( int $errno , string $errstr [, string $errfile [, int $errline [, array $errcontext ]]] )
errno
Le premier paramètre errno, contient le niveau d'erreur, sous la forme d'un entier.
errstr
Le second paramètre errstr, contient le message d'erreur, sous forme de chaîne.
errfile
Le troisième paramètre, optionnel, errfile, contient le nom du fichier dans lequel l'erreur a été identifiée.
errline
Le quatrième paramètre, optionnel, errline, contient le numéro de ligne à laquelle l'erreur a été identifiée.
errcontext
Le cinquième paramètre, optionnel, errcontext, est un tableau qui pointe sur la table des symboles actifs lors de l'erreur. En d'autres termes, errcontext contient un tableau avec toutes les variables qui existaient lorsque l'erreur a été déclenchée. La fonction de gestion d'erreurs de l'utilisateur ne doit pas modifier le contexte d'erreur.

Si la fonction retourne FALSE, alors le gestionnaire d'erreurs normal continue.

error_types

Sert de masque pour appeler la fonction error_handler de la même façon que l'option de configuration error_reporting contrôle les erreurs qui sont affichées. Sans le masque, error_handler sera appelé pour toutes les erreurs, quelle que soit la valeur de error_reporting.

Valeurs de retour

Retourne une chaîne contenant le dernier gestionnaire d'erreurs (s'il existe). Si le gestionnaire d'erreurs natif est utilisé, NULL est retourné. NULL est également retourné dans le cas d'une erreur, comme une fonction de rappel incorrecte. Si le gestionnaire d'erreurs précédent est une méthode d'une classe, cette fonction retournera un tableau indexé de la classe et du nom de la méthode.

Historique

Version Description
5.5.0 error_handler accepte désormais NULL.
5.2.0 Le gestionnaire d'erreurs doit retourner FALSE pour peupler la variable $php_errormsg.

Exemples

Exemple #1 Gestionnaire d'erreurs avec set_error_handler() et trigger_error()

L'exemple ci-dessous illustre l'interception d'erreurs internes avec génération d'erreur et son exploitation dans une fonction utilisateur :

<?php
// Gestionnaire d'erreurs
function myErrorHandler($errno$errstr$errfile$errline)
{
   if (!(
error_reporting() & $errno)) {
        
// Ce code d'erreur n'est pas inclus dans error_reporting()
        
return;
    }

    switch (
$errno) {
    case 
E_USER_ERROR:
        echo 
"<b>Mon ERREUR</b> [$errno$errstr<br />\n";
        echo 
"  Erreur fatale sur la ligne $errline dans le fichier $errfile";
        echo 
", PHP " PHP_VERSION " (" PHP_OS ")<br />\n";
        echo 
"Arrêt...<br />\n";
        exit(
1);
        break;

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

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

    default:
        echo 
"Type d'erreur inconnu : [$errno$errstr<br />\n";
        break;
    }

    
/* Ne pas exécuter le gestionnaire interne de PHP */
    
return true;
}

// Fonction pour tester la gestion d'erreur
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("Type d'entrée incorrect, tableau de valeurs attendu"E_USER_WARNING);
        return 
null;
    }

    
$temp = array();
    foreach(
$vect as $pos => $value) {
        if (!
is_numeric($value)) {
            
trigger_error("La valeur à la position $pos n'est pas un nombre, utilisation 0 (zéro)"E_USER_NOTICE);
            
$value 0;
        }
        
$temp[$pos] = log($scale) * $value;
    }
    return 
$temp;
  }

// Configuration du gestionnaire d'erreurs
$old_error_handler set_error_handler("myErrorHandler");

// Génération de quelques erreurs. Commençons par créer un tableau
echo "vector a\n";
$a = array(23"foo"5.543.321.11);
print_r($a);

// Générons maintenant un second tableau
echo "----\nvector b - a notice (b = log(PI) * a)\n";
/* Valeur à la position $pos n'est pas un nombre, utilisation de 0 (zéro) */
$b scale_by_log($aM_PI);
print_r($b);

// Ceci est un problème, nous avons utilisé une chaîne au lieu d'un tableau
echo "----\nvector c - a warning\n";
/* Type d'entrée incorrect, tableau de valeurs attendu */
$c scale_by_log("non un tablau"2.3);
var_dump($c); // NULL

// Ceci est une erreur critique : le logarithme de zéro ou d'un nombre négatif est indéfini
echo "----\nvector d - fatal error\n";
/* log(x) pour x <= 0 est indéfini, vous utilisez : scale = $scale" */
$d scale_by_log($a, -2.5);
var_dump($d); // Jamais atteint
?>

L'exemple ci-dessus va afficher quelque chose de similaire à :

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>Mon AVERTISSEMENT</b> [1024] La valeur à la position 2 n'est pas un nombre, utilisation de 0 (zéro)<br />
Array
(
    [0] => 2.2894597716988
    [1] => 3.4341896575482
    [2] => 0
    [3] => 6.2960143721717
    [4] => 49.566804057279
    [5] => 24.165247890281
)
----
vector c - an warning
<b>Mon ALERTE</b> [512] Entrée incorrect, tableau de valeurs attendu<br />
NULL
----
vector d - fatal error
<b>Mon ERREUR</b> [256] log(x) for x <= 0 est indéfini, vous utilisez : scale = -2.5<br />
Erreur fatale sur la ligne 36 dans le fichier trigger_error.php, PHP 4.0.2 (Linux)<br />
Abandon...<br />

Voir aussi

add a note add a note

User Contributed Notes 64 notes

up
23
Philip
1 year ago
By this function alone you can not catch fatal errors, there is a simple work around. Below is part of my error.php file which handles errors and exceptions in the application. Before someone complains I'll add that I do not care that I am using globals, this file is part of my mini framework and without the 'config' variable the application would crash anyways.

<?php

/**
* Error handler, passes flow over the exception logger with new ErrorException.
*/
function log_error( $num, $str, $file, $line, $context = null )
{
   
log_exception( new ErrorException( $str, 0, $num, $file, $line ) );
}

/**
* Uncaught exception handler.
*/
function log_exception( Exception $e )
{
    global
$config;
   
    if (
$config["debug"] == true )
    {
        print
"<div style='text-align: center;'>";
        print
"<h2 style='color: rgb(190, 50, 50);'>Exception Occured:</h2>";
        print
"<table style='width: 800px; display: inline-block;'>";
        print
"<tr style='background-color:rgb(230,230,230);'><th style='width: 80px;'>Type</th><td>" . get_class( $e ) . "</td></tr>";
        print
"<tr style='background-color:rgb(240,240,240);'><th>Message</th><td>{$e->getMessage()}</td></tr>";
        print
"<tr style='background-color:rgb(230,230,230);'><th>File</th><td>{$e->getFile()}</td></tr>";
        print
"<tr style='background-color:rgb(240,240,240);'><th>Line</th><td>{$e->getLine()}</td></tr>";
        print
"</table></div>";
    }
    else
    {
       
$message = "Type: " . get_class( $e ) . "; Message: {$e->getMessage()}; File: {$e->getFile()}; Line: {$e->getLine()};";
       
file_put_contents( $config["app_dir"] . "/tmp/logs/exceptions.log", $message . PHP_EOL, FILE_APPEND );
       
header( "Location: {$config["error_page"]}" );
    }
   
    exit();
}

/**
* Checks for a fatal error, work around for set_error_handler not working on fatal errors.
*/
function check_for_fatal()
{
   
$error = error_get_last();
    if (
$error["type"] == E_ERROR )
       
log_error( $error["type"], $error["message"], $error["file"], $error["line"] );
}

register_shutdown_function( "check_for_fatal" );
set_error_handler( "log_error" );
set_exception_handler( "log_exception" );
ini_set( "display_errors", "off" );
error_reporting( E_ALL );
up
12
elad dot yosifon at gmail dot com
1 year ago
<?php
/**
* throw exceptions based on E_* error types
*/
set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
   
// error was suppressed with the @-operator
   
if (0 === error_reporting()) { return false;}
    switch(
$err_severity)
    {
        case
E_ERROR:               throw new ErrorException            ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_WARNING:             throw new WarningException          ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_PARSE:               throw new ParseException            ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_NOTICE:              throw new NoticeException           ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_CORE_ERROR:          throw new CoreErrorException        ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_CORE_WARNING:        throw new CoreWarningException      ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_COMPILE_ERROR:       throw new CompileErrorException     ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_COMPILE_WARNING:     throw new CoreWarningException      ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_USER_ERROR:          throw new UserErrorException        ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_USER_WARNING:        throw new UserWarningException      ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_USER_NOTICE:         throw new UserNoticeException       ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_STRICT:              throw new StrictException           ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_RECOVERABLE_ERROR:   throw new RecoverableErrorException ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_DEPRECATED:          throw new DeprecatedException       ($err_msg, 0, $err_severity, $err_file, $err_line);
        case
E_USER_DEPRECATED:     throw new UserDeprecatedException   ($err_msg, 0, $err_severity, $err_file, $err_line);
    }
});

class
WarningException              extends ErrorException {}
class
ParseException                extends ErrorException {}
class
NoticeException               extends ErrorException {}
class
CoreErrorException            extends ErrorException {}
class
CoreWarningException          extends ErrorException {}
class
CompileErrorException         extends ErrorException {}
class
CompileWarningException       extends ErrorException {}
class
UserErrorException            extends ErrorException {}
class
UserWarningException          extends ErrorException {}
class
UserNoticeException           extends ErrorException {}
class
StrictException               extends ErrorException {}
class
RecoverableErrorException     extends ErrorException {}
class
DeprecatedException           extends ErrorException {}
class
UserDeprecatedException       extends ErrorException {}
up
6
kalle at meizo dot com
4 years ago
This may be of help to someone, who is/was looking for a way to get a backtrace of fatal errors such as maximum memory allocation issues, which can not be handled with user-defined functions, to pin-point the problem:

On a server hosting many sites that share common PHP includes, I set in one spot:

<?php
@ini_set ("error_log", "/my/path/php.err-" . $_SERVER ["HTTP_HOST"] . "-" . $_SERVER ["REMOTE_ADDR"] . "-" . $_SERVER ["REQUEST_METHOD"] . "-" . str_replace ("/", "|", $_SERVER ["REQUEST_URI"]));
?>

I actually used some additional information too from my software that I omitted, but that way, you'll find errors sorted more neatly in for example:-

/my/path/php.err-website.com-127.0.0.1-GET-path|index.html?xyz

And that at least helped me tremendously to then further pin-point where the problem is, as opposed to before just seeing the out of memory and not knowing which site/page it was on (as the PHP error only contains the very latest PHP code where it ran out of memory, which usually is just a shared included file, not the actual page).
up
5
wfinn at riverbed dot com
6 years ago
"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();

?>
up
6
phpmanual at NO_SPHAMnetebb dot com
10 years ago
Given this code:

class CallbackClass {
    function CallbackFunction() {
        // refers to $this
    }

    function StaticFunction() {
        // doesn't refer to $this
    }
}

function NonClassFunction() {
}

there appear to be 3 ways to set a callback function in PHP (using set_error_handler() as an example):

1: set_error_handler('NonClassFunction');

2: set_error_handler(array('CallbackClass', 'StaticFunction'));

3: $o =& new CallbackClass();
   set_error_handler(array($o, 'CallbackFunction'));

The following may also prove useful:

class CallbackClass {
    function CallbackClass() {
        set_error_handler(array(&$this, 'CallbackFunction')); // the & is important
    }
   
    function CallbackFunction() {
        // refers to $this
    }
}

The documentation is not clear in outlining these three examples.
up
2
periklis
4 years ago
How to handle fatal errors in php 5.2:

<?php
register_shutdown_function
('shutdownFunction');
function
shutDownFunction() {
   
$error = error_get_last();
    if (
$error['type'] == 1) {
       
//do your stuff    
   
}
}
?>
up
1
nicolas dot grekas+php at gmail dot com
10 months ago
If you want to be sure that the native PHP error handler is called without resetting the handler stack (as set_error_handler(null) does), you can simply call set_error_handler with $error_types set to zero. This can be especially use full in conjunction with e.g. error_get_last():

<?php

// var_dump or anything else, as this will never be called because of the 0
set_error_handler('var_dump', 0);
@
$undef_var;
restore_error_handler();

// error_get_last() is now in a well known state:
// Undefined variable: undef_var

... // Do something

$e = error_get_last();

...

?>
up
2
dannykopping at gmail dot com
6 months ago
Keep in mind that, when attempting to set a statically-defined error handler on a namespaced class in PHP >= 5.3, you need to use the class namespace:

<?php
set_error_handler
('\\My\\Namespace\\Bob::errorHandler');
?>
up
2
phil at propcom dot co dot uk
11 months ago
It is important to note that the registered SPL autoloader will NOT be called if an E_STRICT error triggers the error handler which, in turn, tries to use classes which are not yet loaded.

In this instance, you should manually load classes required by the error handler.
up
2
stepheneliotdewey at GmailDotCom
7 years ago
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]]] )
up
2
mmtache at yahoo dot com
11 years ago
The @ operator sets the error_reporting() value to 0.
This means you can use it with your own Error Handler too. for example:

function userErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
   if (error_reporting())
echo $errmsg;
    }
set_error_handler("userErrorHandler");

function test(){
trigger_error("Error Message", E_USER_WARNING);
}

@test(); // doesn't output anything
up
1
webmaster at paramiliar dot com
6 years ago
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__);
   

?>
up
1
Thomas
7 years ago
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).
up
1
gotrunko at hotmail dot com
7 years ago
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);
    }
}
?>
up
0
jtrick77 at gmail dot com
10 months ago
For anyone interested in the actual translated error codes and their meanings:

1    E_ERROR (integer)     Fatal run-time errors. These indicate errors that can not be recovered from, such as a memory allocation problem. Execution of the script is halted.    
2    E_WARNING (integer)     Run-time warnings (non-fatal errors). Execution of the script is not halted.    
4    E_PARSE (integer)     Compile-time parse errors. Parse errors should only be generated by the parser.    
8    E_NOTICE (integer)     Run-time notices. Indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script.    
16    E_CORE_ERROR (integer)     Fatal errors that occur during PHP's initial startup. This is like an E_ERROR, except it is generated by the core of PHP.    
32    E_CORE_WARNING (integer)     Warnings (non-fatal errors) that occur during PHP's initial startup. This is like an E_WARNING, except it is generated by the core of PHP.    
64    E_COMPILE_ERROR (integer)     Fatal compile-time errors. This is like an E_ERROR, except it is generated by the Zend Scripting Engine.    
128    E_COMPILE_WARNING (integer)     Compile-time warnings (non-fatal errors). This is like an E_WARNING, except it is generated by the Zend Scripting Engine.    
256    E_USER_ERROR (integer)     User-generated error message. This is like an E_ERROR, except it is generated in PHP code by using the PHP function trigger_error().    
512    E_USER_WARNING (integer)     User-generated warning message. This is like an E_WARNING, except it is generated in PHP code by using the PHP function trigger_error().    
1024    E_USER_NOTICE (integer)     User-generated notice message. This is like an E_NOTICE, except it is generated in PHP code by using the PHP function trigger_error().    
2048    E_STRICT (integer)     Enable to have PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code.    Since PHP 5 but not included in E_ALL until PHP 5.4.0
4096    E_RECOVERABLE_ERROR (integer)     Catchable fatal error. It indicates that a probably dangerous error occurred, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handle (see also set_error_handler()), the application aborts as it was an E_ERROR.    Since PHP 5.2.0
8192    E_DEPRECATED (integer)     Run-time notices. Enable this to receive warnings about code that will not work in future versions.    Since PHP 5.3.0
16384    E_USER_DEPRECATED (integer)     User-generated warning message. This is like an E_DEPRECATED, except it is generated in PHP code by using the PHP function trigger_error().    Since PHP 5.3.0
32767    E_ALL (integer)     All errors and warnings, as supported, except of level E_STRICT prior to PHP 5.4.0.     32767 in PHP 5.4.x, 30719 in PHP 5.3.x, 6143 in PHP 5.2.x, 2047 previously

(Copied from http://php.net/manual/en/errorfunc.constants.php)
up
0
Jacob Slomp
1 year ago
This might be handy if you don't want your clients to see the errors, and you do want to be one step ahead of them.

It emails you the errors even if it's a parse error.

set_error_handler() doesn't work for what I wanted.

<?php
ini_set
('log_errors',TRUE);
ini_set('error_log','tiny_uploads/errors.txt');

if(
$_SERVER['REMOTE_ADDR'] != "YOUR IP ADDRESS"){
   
ini_set('display_errors',false);
}
  
function
byebye(){

       
$dir = dirname(__FILE__);
        if(
file_exists($dir."/tiny_uploads/errors.txt")){
       
           
$errors = file_get_contents($dir."/tiny_uploads/errors.txt");
           
            if(
trim($errors)){
           
               
$head = "From: php_errors@".str_replace('www.','',$_SERVER['HTTP_HOST'])."\r\n";
               
               
$errors .= "---------------------------------------------\n\n";
               
               
$errors .= "\n\nServer Info:\n\n".print_r($_SERVER, 1)."\n\n";
               
$errors .= "---------------------------------------------\n\n";
               
               
$errors .= "\n\nCOOKIE:\n\n".print_r($_COOKIE, 1)."\n\n";
               
$errors .= "---------------------------------------------\n\n";
               
               
$errors .= "\n\nPOST:\n\n".print_r($_POST, 1)."\n\n";
               
$errors .= "---------------------------------------------\n\n";
               
               
$errors .= "\n\nGET:\n\n".print_r($_GET, 1)."\n\n";
               
               
               
mail("YOUR@EMAIL.COM","PHP Error ".$_SERVER['HTTP_HOST']."", $errors , $head);
               
               
$fp = fopen($dir."/tiny_uploads/errors.txt","w+");
               
fputs($fp, "");
               
fclose($fp);   
            }   
        }
}
register_shutdown_function("byebye");
?>
up
1
florian at siweho dot de
9 years ago
@ 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
up
1
Steffen Staehle
9 years ago
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");

?>
up
0
dorphalsig at NOSPAMgmail dot com
2 years ago
This actually works to catch Fatal errors...

<?php
function shutdown()
{
   
$a=error_get_last();
    if(
$a==null)  
        echo
"No errors";
    else
        
print_r($a);
   
}
register_shutdown_function('shutdown');
ini_set('max_execution_time',1 );
sleep(3);
?>

it will output
Array ( [type] => 1 [message] => Maximum execution time of 1 second exceeded [file] => /path/to/file_name.php [line] => 136 )
up
1
mightye (at) mightye (dot) org
10 years ago
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.
up
1
sijmen at digitized dot nl
10 years ago
@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
up
0
francois vespa
3 years ago
This is a note when using php from the terminal (the CLI interface). From the command line, even if you have some kind of error user handler function so STDERR will not display, fatal errors will still cause the PHP interpreter to display error text. There is nothing you can do about that php-wise. If using UNIX/Linux, you can add " 2>/dev/null" at the end of your command to force STDERR not to show
up
0
contact [a] ionisis [.] com
4 years ago
There seems to be no way to access to access the _POST, _GET, etc if you call trigger_error from within a function inside a class file.
up
0
devermin at ti0n dot net
4 years ago
At work I have some code with errors that uncatched are the causes of integrity loss (people calling web services with file_get_contents that fails silently and afterwards insert garbage in the database).

here is the solution I found to transform a specific set of errors into exception and afterwards be able to selectively act (with the error code) regarding categories : 

<?php
ini_set
('error_reporting',E_ALL^E_NOTICE);

## first 10 bits reserved for the initial error number
define('EMASK',(~0)<<10);
define('ECODEMASK',~EMASK);
## categories
define('IOERROR', 1<<10);
define('EMPTYPARMS', 1<<11);
define('FAILURE', 1<<12);
## string error patterns => code

$catch_me=array(
   
"/^(file_get_contents)\((.*)\).*failed to open stream: (.*)/ " =>
        array (
'mesg' => "IO::Failed to open stream with",
               
'code' => IOERROR | FAILURE
       
),
   
"/^fopen\(.*\): Filename cannot be empty/" =>
        array(
'msg' => "Parameters::empty",
               
'code' => EMPTYPARMS
       
)
    );
function
error_2_exception($errno, $errstr, $errfile, $errline,$context) {
    global
$catch_me;
    foreach (
$catch_me as $regexp  => $res) {
        if(
preg_match($regexp,$errstr,$match)){
            throw new
Exception($res['mesg'],$res['code']|( $errno & EMASK ) );
        }
    }
   
/* switch back to PHP internal error handler  */
   
return false;
}
## => want to catch this one
$f=file_get_contents("mlsdkfm");
## dont want to break existing wrong behaviour yet (so not caught)
$f=file_get_contents('');
## magic
set_error_handler("error_2_exception");
## behaviour remains the same
$f=file_get_contents('');
try {
## web services that dont work now raise an exception \o/
$f=file_get_contents("mlsdkfm");
} catch(
Exception $e) {
## and I can group my exception by category
   
echo ( $e->getCode() & FAILURE )  ? "\nEPIC FAIL\n" : "\nbegnine";
}

?>
up
0
quickshiftin at gmail dot com
5 years ago
using the output_buffer as a way to trap fatal errors from php itself, like E_ERROR, cannot offer a complete solution, b/c output buffering is disabled on the cli since 4.3.5 ..
up
0
nizamgok at gmail dot com
5 years ago
I have realized that a few people here mentioned that you cannot capture parse errors (type 4, E_PARSE). This is not true. Here is how I do. I hope this helps someone.

1) Create a "auto_prepend.php" file in the web root and add this:

<?php
register_shutdown_function
('error_alert');

function
error_alert()
{
        if(
is_null($e = error_get_last()) === false)
        {
               
mail('your.email@example.com', 'Error from auto_prepend', print_r($e, true));
        }
}
?>

2) Then add this "php_value auto_prepend_file /www/auto_prepend.php" to your .htaccess file in the web root.

* make sure you change the email address and the path to the file.
up
0
nsg
5 years ago
If using E_USER_ERROR in conjunction with a custom error-handler, we are faced with an annoying choice:

If you choose to die() on such errors, __destruct()ors can still function, but we can't then return false and have the inbuilt handler log the error.

If you return false thus allowing the error to be logged, the script will halt, exit() style, and __destruct()'s won't happen.

It seems the only solutions in such a case is to a) log your own errors, or b) don't use E_USER_ERROR.
up
0
Marcelius
5 years ago
Another way to catch PHP's fatal errors:

<?php
    error_reporting
(E_ALL);
   
ini_set('display_errors', 0);

    function
shutdown(){
       
$isError = false;
        if (
$error = error_get_last()){
            switch(
$error['type']){
                case
E_ERROR:
                case
E_CORE_ERROR:
                case
E_COMPILE_ERROR:
                case
E_USER_ERROR:
                   
$isError = true;
                    break;
            }
        }

        if (
$isError){
            echo
"Script execution halted ({$error['message']})";
        } else {
            echo
"Script completed";
        }
    }

   
register_shutdown_function('shutdown');
?>

Note that this will only catch runtime errors. So calling a method in a non existing class, or declaring a function twice does not trigger the shutdown handler.
up
0
jonbarnett at gmail dot com
6 years ago
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
up
0
etienne at perval dot fr
6 years ago
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.
up
0
m0sh3 at hotmail dot com
6 years ago
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";
}
// */
?>
up
0
michal dot kocarek at NO_SPAM dot seznam dot cz
6 years ago
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;
}
?>
up
0
ash
7 years ago
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);
    }
}

?>
up
0
stepheneliotdewey at GmailDotCom
7 years ago
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.
up
0
greg sidberry[poetics5 at yahoo dot com]
7 years ago
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;
}
up
0
silkensedai at online dot fr
7 years ago
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
?>
up
0
elven_rangers at yahoo dot com
7 years ago
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.
up
0
mail at chernousov dot com
7 years ago
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
up
0
alexey.kupershtokh.gmail
7 years ago
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);
up
0
dk at brightbyte dot de
8 years ago
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.
up
0
jla
8 years ago
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>');
up
0
kariedoo
8 years ago
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
up
0
docey
8 years ago
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.
up
0
errd
8 years ago
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);

?>
up
0
Anonymous
8 years ago
To honor the value of PHP's error_reporting() function, use:

<?
 
if( ($level & error_reporting()) == 0 ) return;
?>
up
0
Gulopine
8 years ago
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.
up
0
ia [AT] zoznam [DOT] sk
8 years ago
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)
up
0
eregon at eregon dot info
9 years ago
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).
up
0
dawiddr at gmail dot com
9 years ago
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.
up
0
frank at ethisoft dot nl
9 years ago
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.
up
0
jgiglio at netmar dot com
9 years ago
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.
up
0
Sukender
10 years ago
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).
up
0
Joe
10 years ago
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.
up
0
Cezary Tomczak
10 years ago
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
up
0
erwin at isiz dot nl
10 years ago
@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.
up
0
jayp at groovejob dot com
10 years ago
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
up
0
sijmen at digitized dot nl
10 years ago
@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, 'handler')); // The '&' operator doesn't have any effect
   
}
}

$eh = new error;
$eh->setText('Error! <br>'); // Will not get set

trigger_error('text', E_USER_ERROR); // prints '!!'
?>

Proof of concept
http://trouby.digitized.nl/set_error_handler.php
http://trouby.digitized.nl/set_error_handler.php?source=1
up
0
skyrl at free dot fr
10 years ago
in reaction to the last '29-Mar-2004 11:13' post, just have to say that's normal the values are not "saved" in your error handler object. because the error object of the handler is not the same object as the one you instantiate...

You have to write set_error_handler(array(&this, 'my_error_handler')). The & is important for php to know that your error handler belongs to the same instance you allocate.
up
0
Anonymous
10 years ago
It seems that when you're letting PHP know that you have a custom  error handler, you're not able to -update/set new- variables inside the class. Example:

<?php
class error {
   var
$error;

   function
error() {
      
$this->setIni();    // this causes PHP to ignore all other changes to the class.
  
}

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

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

   function
setIni() {
      
set_error_handler(array($this, 'handler'));
   }
}

$eh = new error;
$eh->setText('Error! <br>');  // this will not be saved

trigger_error('text', E_USER_ERROR);
// prints '!!'
?>

How it should be done:
<?php
class error {
   var
$error;

   function
error() {
        
// dont let PHP know of our error handler yet
  
}

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

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

   function
setIni() {
      
set_error_handler(array($this, 'handler'));
   }
}

$eh = new error;
$eh->setText('Error! <br>');  // this WILL work
$eh->setIni();  // call this method when you're ready with configuring the class. All other methods that will be called will have no effect on the errorHandling by PHP

trigger_error('text', E_USER_ERROR);
// prints 'Error! <br>!!'
?>
up
0
Thomas Staunton
11 years ago
The best way, I have found to use a class/object as an error handler is to define a class, add your desired error handling function into the constructor and then call set_error_handler() to the name of your function, thats it. e.g.

Class Error {

  Function Error() {
    Function HandleError($n, $m, $f, $l){
      print_r(debug_backtrace());
    }
    set_error_handler('HandleError');
  }
}
up
0
bob at db dot org
11 years ago
The documentation on this page kindly offers the following on using (class) methods as error handlers:

Note:  Instead of a function name, an array containing an object reference and a method name can also be supplied. (Since PHP 4.3.0)

Since that's all it says about the subject, I thought I'd offer a sample implementation to show how this can be used:

<?php

       
class error {

                var
$conf;
                var
$lang;

                function
error($conf, $lang) {
                       
$this->conf = $conf;
                       
$this->lang = $lang;

                       
set_error_handler(array(&$this, 'handler'));
                }

                function
handler($no, $str, $file, $line, $ctx) {
                        echo
'<pre>';
                        echo
'no   : ' . $no . "\n";
                        echo
'str  : ' . $str . "\n";
                        echo
'file : ' . $file . "\n";
                        echo
'line : ' . $line . "\n";
                        echo
'ctx  : ';
                       
print_r($ctx);
                        echo
'</pre>';
                }

        }
?>
up
0
roy
12 years ago
Useful thing to note - if your error handler throws an error in itself, PHP is smart enough to use the deault error handler to handle it. This way, you don't end up in infinite flaming loops of death. This seems to be true, at least, in PHP 4.2.

('Course, there are ways to create your handler to handle even this situation, but it's probably best left this way for general purposes.)
up
0
publicmail at macfreek dot nl
12 years ago
Note: If you have a custom error handler and use assert(), you MUST set:

assert_options (ASSERT_WARNING, 0);

Otherwise, no output whatsoever will ever be shown if an assert fails.
up
0
ned at wgtech dot com
12 years ago
Just spent two days trying to find some method where a class can handle errors thrown at my convienience. After fighting with the pitfalls of this problem this is what I came up with. Hope it helps someone else save a little time. Its nice because all instances of this class will point to the same array that stores the errors.

class ApplicationObject {
    var $error_List;
   
    function ApplicationObject() {
        set_error_handler('trapError');
        $this->error_List = &trapError();
    }

}

function &trapError() {
    static $error_Vals = array();

    if (func_num_args()==5) { // Error Event has been passed
        $error_Vals[] = array(    'err_no' => func_get_arg(0), 'err_text' => func_get_arg(1), 'err_file' => func_get_arg(2), 'err_line' => func_get_arg(3), 'err_vars'=>func_get_arg(4));
    }
    if (func_num_args()==0) { // Setup call. Return reference
        return $error_Vals;
    }
}
To Top