Php register error function



Exceptions

Table of Contents

PHP has an exception model similar to that of other programming languages. An exception can be throw n, and caught (» catch ed») within PHP. Code may be surrounded in a try block, to facilitate the catching of potential exceptions. Each try must have at least one corresponding catch or finally block.

If an exception is thrown and its current function scope has no catch block, the exception will «bubble up» the call stack to the calling function until it finds a matching catch block. All finally blocks it encounters along the way will be executed. If the call stack is unwound all the way to the global scope without encountering a matching catch block, the program will terminate with a fatal error unless a global exception handler has been set.

The thrown object must be an instanceof Throwable . Trying to throw an object that is not will result in a PHP Fatal Error.

As of PHP 8.0.0, the throw keyword is an expression and may be used in any expression context. In prior versions it was a statement and was required to be on its own line.

catch

A catch block defines how to respond to a thrown exception. A catch block defines one or more types of exception or error it can handle, and optionally a variable to which to assign the exception. (The variable was required prior to PHP 8.0.0.) The first catch block a thrown exception or error encounters that matches the type of the thrown object will handle the object.

Multiple catch blocks can be used to catch different classes of exceptions. Normal execution (when no exception is thrown within the try block) will continue after that last catch block defined in sequence. Exceptions can be throw n (or re-thrown) within a catch block. If not, execution will continue after the catch block that was triggered.

When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching catch block. If an exception is not caught, a PHP Fatal Error will be issued with an » Uncaught Exception . » message, unless a handler has been defined with set_exception_handler() .

As of PHP 7.1.0, a catch block may specify multiple exceptions using the pipe ( | ) character. This is useful for when different exceptions from different class hierarchies are handled the same.

As of PHP 8.0.0, the variable name for a caught exception is optional. If not specified, the catch block will still execute but will not have access to the thrown object.

finally

A finally block may also be specified after or instead of catch blocks. Code within the finally block will always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.

One notable interaction is between the finally block and a return statement. If a return statement is encountered inside either the try or the catch blocks, the finally block will still be executed. Moreover, the return statement is evaluated when encountered, but the result will be returned after the finally block is executed. Additionally, if the finally block also contains a return statement, the value from the finally block is returned.

Global exception handler

If an exception is allowed to bubble up to the global scope, it may be caught by a global exception handler if set. The set_exception_handler() function can set a function that will be called in place of a catch block if no other block is invoked. The effect is essentially the same as if the entire program were wrapped in a try — catch block with that function as the catch .

Notes

Internal PHP functions mainly use Error reporting, only modern Object-oriented extensions use exceptions. However, errors can be easily translated to exceptions with ErrorException. This technique only works with non-fatal errors, however.

Example #1 Converting error reporting to exceptions

function exceptions_error_handler ( $severity , $message , $filename , $lineno ) <
throw new ErrorException ( $message , 0 , $severity , $filename , $lineno );
>

Examples

Example #2 Throwing an Exception

function inverse ( $x ) <
if (! $x ) <
throw new Exception ( ‘Division by zero.’ );
>
return 1 / $x ;
>

try <
echo inverse ( 5 ) . «\n» ;
echo inverse ( 0 ) . «\n» ;
> catch ( Exception $e ) <
echo ‘Caught exception: ‘ , $e -> getMessage (), «\n» ;
>

// Continue execution
echo «Hello World\n» ;
?>

The above example will output:

Example #3 Exception handling with a finally block

function inverse ( $x ) <
if (! $x ) <
throw new Exception ( ‘Division by zero.’ );
>
return 1 / $x ;
>

try <
echo inverse ( 5 ) . «\n» ;
> catch ( Exception $e ) <
echo ‘Caught exception: ‘ , $e -> getMessage (), «\n» ;
> finally <
echo «First finally.\n» ;
>

try <
echo inverse ( 0 ) . «\n» ;
> catch ( Exception $e ) <
echo ‘Caught exception: ‘ , $e -> getMessage (), «\n» ;
> finally <
echo «Second finally.\n» ;
>

// Continue execution
echo «Hello World\n» ;
?>

The above example will output:

Example #4 Interaction between the finally block and return

function test () <
try <
throw new Exception ( ‘foo’ );
> catch ( Exception $e ) <
return ‘catch’ ;
> finally <
return ‘finally’ ;
>
>

The above example will output:

Example #5 Nested Exception

class Test <
public function testing () <
try <
try <
throw new MyException ( ‘foo!’ );
> catch ( MyException $e ) <
// rethrow it
throw $e ;
>
> catch ( Exception $e ) <
var_dump ( $e -> getMessage ());
>
>
>

$foo = new Test ;
$foo -> testing ();

The above example will output:

Читайте также:  Run time error 53 что это за ошибка

Example #6 Multi catch exception handling

class MyOtherException extends Exception

class Test <
public function testing () <
try <
throw new MyException ();
> catch ( MyException | MyOtherException $e ) <
var_dump ( get_class ( $e ));
>
>
>

$foo = new Test ;
$foo -> testing ();

The above example will output:

Example #7 Omitting the caught variable

Only permitted in PHP 8.0.0 and later.

class SpecificException extends Exception <>

function test () <
throw new SpecificException ( ‘Oopsie’ );
>

try <
test ();
> catch ( SpecificException ) <
print «A SpecificException was thrown, but we don’t care about the details.» ;
>
?>

Example #8 Throw as an expression

Only permitted in PHP 8.0.0 and later.

class SpecificException extends Exception <>

function test () <
do_something_risky () or throw new Exception ( ‘It did not work’ );
>

try <
test ();
> catch ( Exception $e ) <
print $e -> getMessage ();
>
?>

User Contributed Notes 13 notes

If you intend on creating a lot of custom exceptions, you may find this code useful. I’ve created an interface and an abstract exception class that ensures that all parts of the built-in Exception class are preserved in child classes. It also properly pushes all information back to the parent constructor ensuring that nothing is lost. This allows you to quickly create new exceptions on the fly. It also overrides the default __toString method with a more thorough one.

interface IException
<
/* Protected methods inherited from Exception class */
public function getMessage (); // Exception message
public function getCode (); // User-defined Exception code
public function getFile (); // Source filename
public function getLine (); // Source line
public function getTrace (); // An array of the backtrace()
public function getTraceAsString (); // Formated string of trace

/* Overrideable methods inherited from Exception class */
public function __toString (); // formated string for display
public function __construct ( $message = null , $code = 0 );
>

abstract class CustomException extends Exception implements IException
<
protected $message = ‘Unknown exception’ ; // Exception message
private $string ; // Unknown
protected $code = 0 ; // User-defined exception code
protected $file ; // Source filename of exception
protected $line ; // Source line of exception
private $trace ; // Unknown

public function __construct ( $message = null , $code = 0 )
<
if (! $message ) <
throw new $this ( ‘Unknown ‘ . get_class ( $this ));
>
parent :: __construct ( $message , $code );
>

public function __toString ()
<
return get_class ( $this ) . » ‘ < $this ->message > ‘ in < $this ->file > ( < $this ->line > )\n»
. » < $this ->getTraceAsString ()> » ;
>
>
?>

Now you can create new exceptions in one line:

class TestException extends CustomException <>
?>

Here’s a test that shows that all information is properly preserved throughout the backtrace.

function exceptionTest ()
<
try <
throw new TestException ();
>
catch ( TestException $e ) <
echo «Caught TestException (‘ < $e ->getMessage ()> ‘)\n < $e >\n» ;
>
catch ( Exception $e ) <
echo «Caught Exception (‘ < $e ->getMessage ()> ‘)\n < $e >\n» ;
>
>

echo » ;
?>

Here’s a sample output:

Источник

set_exception_handler

(PHP 5, PHP 7, PHP 8)

set_exception_handler — Sets a user-defined exception handler function

Description

Sets the default exception handler if an exception is not caught within a try/catch block. Execution will stop after the callback is called.

Parameters

The function to be called when an uncaught exception occurs. This handler function needs to accept one parameter, which will be the Throwable object that was thrown. Both Error and Exception implement the Throwable interface. This is the handler signature:

null may be passed instead, to reset this handler to its default state.

Return Values

Returns the previously defined exception handler, or null on error. If no previous handler was defined, null is also returned.

Examples

Example #1 set_exception_handler() example

function exception_handler ( Throwable $exception ) <
echo «Uncaught exception: » , $exception -> getMessage (), «\n» ;
>

throw new Exception ( ‘Uncaught Exception’ );
echo «Not Executed\n» ;
?>

See Also

  • restore_exception_handler() — Restores the previously defined exception handler function
  • restore_error_handler() — Restores the previous error handler function
  • error_reporting() — Sets which PHP errors are reported
  • PHP 5 Exceptions

User Contributed Notes 18 notes

Things you should be aware of:

An exception handler handles exceptions that were not caught before. It is the nature of an exception that it discontinues execution of your program — since it declares an exceptional situation in which the program cannot continue (except you catch it).

Since it has not been catched your code signals it is not being aware of the situation and cant go on.

This implies: returning to the script is simply impossible when the exception handler has already been called, since an uncaught exception is not a notice. use your own debug- or notice-log-system for things like that.

Furthermore: While is is still possible to call functions from your script, since the exception handler has already been called exceptions bubbling from that piece of code won’t trigger the exception handler again. php will die without leaving any information apart form «uncaught exception with unknown stack frame». So if you call functions from your script, make sure that you catch any exceptions that possibly occur via try..catch inside the exception handler.

For those of you who misinterpreted the essential meaning of the exception handler: it’s only use is to handle the abortion of your script gracefully, e.g. in a project like facebook or wikipedia: render a nice error page, eventually hiding information which shall not leak into the public (instead you may want to write to your log or mail the sys-admin or stuff like that).

Читайте также:  Command call rpc error

In other words: Redirecting all php-errors form an error-handler using exceptions — including notices — is a very dumb idea, if you do not intend having your script aborted everytime you didn’t set a variable (for example).

As of PHP 7.4, an exception thrown within the user-defined shutdown function can be caught by the user-defined exception handler.

(
function( $level , $error , $file , $line ) <
if( 0 === error_reporting ()) <
return false ;
>
throw new ErrorException ( $error , — 1 , $level , $file , $line );
>,
E_ALL
);

register_shutdown_function (function() <
$error = error_get_last ();
if( $error ) <
throw new ErrorException ( $error [ ‘message’ ], — 1 , $error [ ‘type’ ], $error [ ‘file’ ], $error [ ‘line’ ]);
>
>);

set_exception_handler (function( $exception ) <
// . more code .
>);

If you want a class instance to handle the exception, this is how you do it :

class example <
public function __construct () <
@ set_exception_handler (array( $this , ‘exception_handler’ ));
throw new Exception ( ‘DOH!!’ );
>

public function exception_handler ( $exception ) <
print «Exception Caught: » . $exception -> getMessage () . «\n» ;
>
>

$example = new example ;

?>

See the first post (Sean’s) for a static example. As Sean points out, the exception_handler function must be declared public.

A behaviour not documented or discussed enough, yet pretty common is that is that if an exception is thrown from the global exception handler then a fatal error occurs (Exception thrown without a stack frame). That is, if you define your own global exception handler by calling set_exception_handler() and you throw an exception from inside it then this fatal error occurs. It is only natural though, as the callback defined by set_exception_handler() is only called on uncaught (unhandled) exceptions so if you throw one from there then you get this fatal error as there is no exception handler left (you override the php internal one by calling set_exception_handler()), hence no stack frame for it.

function myExceptionHandler ( Exception $ex )
<
throw $ex ;
>

throw new Exception ( «This should cause a fatal error and this message will be lost» );

?>

Will cause a Fatal error: Exception thrown without a stack frame

If you skip/comment the set_exception_handler(«. «) line then the internal PHP global handler will catch the exception and output the exception message and trace (as string) to the browser, allowing you to at least see the exception message.

While it is a very good idea to always define your own global exception handler by using the set_exception_handler() function, you should pay attention and never throw an exception from it (or if you do then catch it).

Finally, every serious coder should use an IDE with debugging capabilities. Tracking down an error like this becomes a trivial matter by using simple debugging «Step into» commands (I for one recommend Zend IDE v5.2 at the moment of this writing). I have seen numerous messages on the internet with people wondering why this message pops up.

p.s. Other causes for this error which are somehow unrelated to this is when you throw an exception from a destructor (the reasons behind that are similar though, the global handler might no longer exist due to the php engine shutting the page down).

On GNU/Linux, When an exception handler is called, PHP will end with exit status code 0 instead of 255.

You can change the exit status code with an exit() call at the end of your custom error handler.

If you’re handling sensitive data and you don’t want exceptions logging details such as variable contents when you throw them, you may find yourself frustratedly looking for the bits and pieces that make up a normal stack trace output, so you can retain its legibility but just alter a few things. In that case, this may help you:

function exceptionHandler ( $exception ) <

// these are our templates
$traceline = «#%s %s(%s): %s(%s)» ;
$msg = «PHP Fatal error: Uncaught exception ‘%s’ with message ‘%s’ in %s:%s\nStack trace:\n%s\n thrown in %s on line %s» ;

// alter your trace as you please, here
$trace = $exception -> getTrace ();
foreach ( $trace as $key => $stackPoint ) <
// I’m converting arguments to their type
// (prevents passwords from ever getting logged as anything other than ‘string’)
$trace [ $key ][ ‘args’ ] = array_map ( ‘gettype’ , $trace [ $key ][ ‘args’ ]);
>

// build your tracelines
$result = array();
foreach ( $trace as $key => $stackPoint ) <
$result [] = sprintf (
$traceline ,
$key ,
$stackPoint [ ‘file’ ],
$stackPoint [ ‘line’ ],
$stackPoint [ ‘function’ ],
implode ( ‘, ‘ , $stackPoint [ ‘args’ ])
);
>
// trace always ends with


$result [] = ‘#’ . ++ $key . ‘
‘ ;

// write tracelines into main template
$msg = sprintf (
$msg ,
get_class ( $exception ),
$exception -> getMessage (),
$exception -> getFile (),
$exception -> getLine (),
implode ( «\n» , $result ),
$exception -> getFile (),
$exception -> getLine ()
);

// log or echo as you please
error_log ( $msg );
>

?>

If you’re not a fan of sprintf() or the duplicate $exception->getFile() and $exception->getLine() calls you can of course replace that as you like — consider this a mere compilation of the parts.

Hey all, i’ve just started to use the exception suite instead of the normal PHP error suite. For those of you looking for an object orientated way to do this without looking down at Glen and Sean’s examples (Lesson 1: ALWAYS read the logs!), here you go:

Читайте также:  System runtime remoting exception

class NewException extends Exception
<
public function __construct ( $message , $code = NULL )
<
parent :: __construct ( $message , $code );
>

public function __toString ()
<
return «Code: » . $this -> getCode () . «
Message: » . htmlentities ( $this -> getMessage ());
>

public function getException ()
<
print $this ; // This will print the return from the above method __toString()
>

public static function getStaticException ( $exception )
<
$exception -> getException (); // $exception is an instance of this class
>
>

set_exception_handler (array( «NewException» , «getStaticException» ));
throw new NewException ( «Catch me. » , 69 );

?>

Let me know if i’m missing something obvious as I left my glasses at home and I just came back from the Melbourne cup (If I won then I wouldn’t be at work still!).

Your exception handler is configured to be the handler for all exceptions, yet if a basic ‘Exception’ is thrown, your static method will error because ‘Exception’s do not have ‘getException’. Because of this I don’t see a real purpose to making the uncaught handler a class that extends Exception.

I do like the idea of using static methods of a general Exception handling class.

class ExceptionHandler <
public static function printException ( Exception $e )
<
print ‘Uncaught ‘ . get_class ( $e ). ‘, code: ‘ . $e -> getCode () . «
Message: » . htmlentities ( $e -> getMessage ()). «\n» ;
>

public static function handleException ( Exception $e )
<
self :: printException ( $e );
>
>

set_exception_handler (array( «ExceptionHandler» , «handleException» ));

class NewException extends Exception <>
try <
throw new NewException ( «Catch me once» , 1 );
> catch ( Exception $e ) <
ExceptionHandler :: handleException ( $e );
>

throw new Exception ( «Catch me twice» , 2 );
?>

Gives:
Uncaught NewException, code: 1
Message: Catch me once
Uncaught Exception, code: 2
Message: Catch me twice

There are much more interesting things that can be done like reformating and optionally displaying or emailing them. But this class acts a nice container for those functions.

Using the ‘set_exception_handler’ function within a class, the defined ‘exception_handler’ method must be declared as ‘public’ (preferrable ‘public static’ if you use the «array(‘example’, ‘exception_handler’)» syntax).

class example <
public function __construct () <
@ set_exception_handler (array( ‘example’ , ‘exception_handler’ ));
throw new Exception ( ‘DOH!!’ );
>

public static function exception_handler ( $exception ) <
print «Exception Caught: » . $exception -> getMessage () . «\n» ;
>
>

$example = new example ;

echo «Not Executed\n» ;
?>

Declaring the ‘exception_handler’ function as ‘private’ causes a FATAL ERROR.

[derick: red. updated statement about static a bit]

For those of you wanting to convert PHP errors to ErrorExceptions (useful), but frustrated with the script being halted on every E_NOTICE et al. In your error handler, simply create the ErrorException, and then either throw it (script halted), or pass the object directly (script continues) to your exception handler function.

const EXIT_ON_ALL_PHP_ERRORS = false ; // or true

function proc_error ( $errno , $errstr , $errfile , $errline )
<
$e = new ErrorException ( $errstr , 0 , $errno , $errfile , $errline );

if ( EXIT_ON_ALL_PHP_ERRORS ) <
throw $e ; // This will halt your script.
> else <
proc_exception ( $e ); // This will let it continue.
>
>

set_error_handler ( «proc_error» );
set_exception_handler ( «proc_exception» );
?>

You could further customize the error severity level (from $errno, match bitmasks with error level constants) at which the script is halted or allowed to continue. The above simply allows passthru for PHP errors’ default behavior.

If your exception handler is receiving both error ErrorExceptions (with severity level etc.) and other types of uncaught Exceptions, then use a if ( $e instanceof ErrorException ) < // . >?> condition to deal with the variance. I had to further wrap it into a try < $errno = $e ->getSeverity (); > catch ( Exception $x ) < $errno = 0 >. ?> , because some EE-s were mysteriously lacking the severity level property (yet to dig in and find out why).

Thanks to mastabog we know that throwing an exception within the exception handler will trigger a fatal error and a debugging nightmare. To avoid throwing an exception within there should be easy.

However, if you use a custom error handler to convert errors to ErrorExceptions suddenly there are a multitude of new ways to accidentally throw exceptions within the exception handler.

function error_handler ( $code , $message , $file , $line )
<
if ( 0 == error_reporting ())
<
return;
>
throw new ErrorException ( $message , 0 , $code , $file , $line );
>
function exception_handler ( $e )
<
// . normal exception stuff goes here
print $undefined ; // This is the underlying problem
>
set_error_handler ( «error_handler» );
set_exception_handler ( «exception_handler» );
throw new Exception ( «Just invoking the exception handler» );
?>
Output: Fatal error: Exception thrown without a stack frame in Unknown on line 0

The best way I have found to avoid this is to wrap up everything in the exception handler in a try/catch block.
function exception_handler ( $e )
<
try
<
// . normal exception stuff goes here
print $undefined ; // This is the underlying problem
>
catch ( Exception $e )
<
print get_class ( $e ). » thrown within the exception handler. Message: » . $e -> getMessage (). » on line » . $e -> getLine ();
>
>
?>
Output: ErrorException thrown within the exception handler. Message: Undefined variable: undefined on line 14

This speeds up debugging and offers some scalability to any other exceptions accidentally thrown within the exception handler.

Another solution is to restore the error handler at the beginning of the exception handler. While this is a silver bullet in terms of avoiding the ErrorExceptions, debugging messages then rely on the error_reporting() level and the display_errors directive. Why mention this? It might be preferable for production code since we care more about hiding errors from users than convenient debugging messages.

Источник

Оцените статью
toolgir.ru
Adblock
detector