Php вызов ошибки

Table of Contents

  • Extending Exceptions

PHP has an exception model similar to that of other programming
languages. An exception can be thrown, and caught («catched») 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 thrown (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 trycatch block with that function as the catch.

Notes

Note:

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


<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new
ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');
?>

Examples

Example #2 Throwing an Exception


<?php
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 Worldn";
?>

The above example will output:

0.2
Caught exception: Division by zero.
Hello World

Example #3 Exception handling with a finally block


<?php
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 Worldn";
?>

The above example will output:

0.2
First finally.
Caught exception: Division by zero.
Second finally.
Hello World

Example #4 Interaction between the finally block and return


<?phpfunction test() {
try {
throw new
Exception('foo');
} catch (
Exception $e) {
return
'catch';
} finally {
return
'finally';
}
}

echo

test();
?>

The above example will output:

Example #5 Nested Exception


<?phpclass MyException extends 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:

Example #6 Multi catch exception handling


<?phpclass MyException extends Exception { }

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.


<?phpclass 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.


<?phpfunction test() {
do_something_risky() or throw new Exception('It did not work');
}

try {

test();
} catch (
Exception $e) {
print
$e->getMessage();
}
?>

ask at nilpo dot com

14 years ago


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.

<?php
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;                             // Unknownpublic 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:

<?php
class TestException extends CustomException {}
?>

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

<?php
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

'<pre>' . exceptionTest() . '</pre>';
?>

Here's a sample output:

Caught TestException ('Unknown TestException')
TestException 'Unknown TestException' in C:xampphtdocsCustomExceptionCustomException.php(31)
#0 C:xampphtdocsCustomExceptionExceptionTest.php(19): CustomException->__construct()
#1 C:xampphtdocsCustomExceptionExceptionTest.php(43): exceptionTest()
#2 {main}


Johan

12 years ago


Custom error handling on entire pages can avoid half rendered pages for the users:

<?php
ob_start
();
try {
   
/*contains all page logic
    and throws error if needed*/
   
...
} catch (
Exception $e) {
 
ob_end_clean();
 
displayErrorPage($e->getMessage());
}
?>


christof+php[AT]insypro.com

5 years ago


In case your E_WARNING type of errors aren't catchable with try/catch you can change them to another type of error like this:

<?php
    set_error_handler
(function($errno, $errstr, $errfile, $errline){
            if(
$errno === E_WARNING){
               
// make it more serious than a warning so it can be caught
               
trigger_error($errstr, E_ERROR);
                return
true;
            } else {
               
// fallback to default php error handler
               
return false;
            }
    });

    try {

// code that might result in a E_WARNING
   
} catch(Exception $e){
           
// code to handle the E_WARNING (it's actually changed to E_ERROR at this point)
   
} finally {
           
restore_error_handler();
    }
?>


lscorionjs at gmail dot com

4 months ago


<?phptry {
 
$str = 'hi';
  throw new
Exception();
} catch (
Exception) {
 
var_dump($str);
} finally {
 
var_dump($str);
}
?>

Output:
string(2) "hi"
string(2) "hi"

Shot (Piotr Szotkowski)

14 years ago


‘Normal execution (when no exception is thrown within the try block, *or when a catch matching the thrown exception’s class is not present*) will continue after that last catch block defined in sequence.’

‘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().’

These two sentences seem a bit contradicting about what happens ‘when a catch matching the thrown exception’s class is not present’ (and the second sentence is actually correct).


Simo

8 years ago


#3 is not a good example. inverse("0a") would not be caught since (bool) "0a" returns true, yet 1/"0a" casts the string to integer zero and attempts to perform the calculation.

daviddlowe dot flimm at gmail dot com

5 years ago


Starting in PHP 7, the classes Exception and Error both implement the Throwable interface. This means, if you want to catch both Error instances and Exception instances, you should catch Throwable objects, like this:

<?phptry {
    throw new
Error( "foobar" );
   
// or:
    // throw new Exception( "foobar" );
}
catch (
Throwable $e) {
   
var_export( $e );
}
?>


Edu

9 years ago


The "finally" block can change the exception that has been throw by the catch block.

<?php
try{
        try {
                throw new
Exception("Hello");
        } catch(
Exception $e) {
                echo
$e->getMessage()." catch inn";
                throw
$e;
        } finally {
                echo
$e->getMessage()." finally n";
                throw new
Exception("Bye");
        }
} catch (
Exception $e) {
        echo
$e->getMessage()." catch outn";
}
?>

The output is:

Hello catch in
Hello finally
Bye catch out


mlaopane at gmail dot com

5 years ago


<?php/**
* You can catch exceptions thrown in a deep level function
*/
function employee()
{
    throw new
Exception("I am just an employee !");
}

function

manager()
{
   
employee();
}

function

boss()
{
    try {
       
manager();
    } catch (
Exception $e) {
        echo
$e->getMessage();
    }
}
boss(); // output: "I am just an employee !"

telefoontoestel at nospam dot org

8 years ago


When using finally keep in mind that when a exit/die statement is used in the catch block it will NOT go through the finally block.

<?php
try {
    echo
"try block<br />";
    throw new
Exception("test");
} catch (
Exception $ex) {
    echo
"catch block<br />";
} finally {
    echo
"finally block<br />";
}
// try block
// catch block
// finally block
?>

<?php
try {
    echo
"try block<br />";
    throw new
Exception("test");
} catch (
Exception $ex) {
    echo
"catch block<br />";
    exit(
1);
} finally {
    echo
"finally block<br />";
}
// try block
// catch block
?>


Tom Polomsk

8 years ago


Contrary to the documentation it is possible in PHP 5.5 and higher use only try-finally blocks without any catch block.

Sawsan

11 years ago


the following is an example of a re-thrown exception and the using of getPrevious function:

<?php

$name

= "Name";//check if the name contains only letters, and does not contain the word nametry
   {
   try
     {
      if (
preg_match('/[^a-z]/i', $name))
       {
           throw new
Exception("$name contains character other than a-z A-Z");
       }  
       if(
strpos(strtolower($name), 'name') !== FALSE)
       {
          throw new
Exception("$name contains the word name");
       }
       echo
"The Name is valid";
     }
   catch(
Exception $e)
     {
     throw new
Exception("insert name again",0,$e);
     }
   }

catch (

Exception $e)
   {
   if (
$e->getPrevious())
   {
    echo
"The Previous Exception is: ".$e->getPrevious()->getMessage()."<br/>";
   }
   echo
"The Exception is: ".$e->getMessage()."<br/>";
   }
?>


ilia-yats at ukr dot net

5 months ago


Note some undocumented details about exceptions thrown from 'finally' blocks.

When exception is thrown from 'finally' block, it overrides the original not-caught (or re-thrown) exception. So the behavior is similar to 'return': value returned from 'finally' overrides the one returned earlier. And the original exception is automatically appended to the exceptions chain, i.e. becomes 'previous' for the new one. Example:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } finally {
        throw new
Exception('thrown from finally');
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// thrown from try
?>

Example with re-throwing:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } catch (
Exception $e) {
        throw new
Exception('thrown from catch');
    } finally {
        throw new
Exception('thrown from finally');
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// thrown from catch
?>

The same happens even if explicitly pass null as previous exception:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } finally {
        throw new
Exception('thrown from finally', null, null);
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// thrown from try
?>

Also it is possible to pass previous exception explicitly, the 'original' one will be still appended to the chain, e.g.:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } finally {
        throw new
Exception(
           
'thrown from finally',
           
null,
            new
Exception('Explicitly set previous!')
        );
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// Explicitly set previous!
// thrown from try
?>

This seems to be true for versions 5.6-8.2.


Daan

1 year ago


I would like to emphasise that you can not rethrow an Exception inside a catch-block and expect that the next catch-block will handle it.

<?php try {
    throw new
RuntimeException('error');           
} catch (
RuntimeException $e) {
    throw
$e;
} catch (
Exception $e) {
   
// this will not be executed[
}
?>


(PHP 4 >= 4.0.1, PHP 5, PHP 7, PHP 8)

trigger_errorGenerates a user-level error/warning/notice message

Description

trigger_error(string $message, int $error_level = E_USER_NOTICE): bool

This function is useful when you need to generate a particular response to
an exception at runtime.

Parameters

message

The designated error message for this error. It’s limited to 1024
bytes in length. Any additional characters beyond 1024 bytes will be
truncated.

error_level

The designated error type for this error. It only works with the E_USER
family of constants, and will default to E_USER_NOTICE.

Return Values

This function returns false if wrong error_level is
specified, true otherwise.

Examples

Example #1 trigger_error() example

See set_error_handler() for a more extensive example.


<?php
if ($divisor == 0) {
trigger_error("Cannot divide by zero", E_USER_ERROR);
}
?>

Notes

Warning

HTML entities in message are not
escaped. Use htmlentities() on the message if
the error is to be displayed in a browser.

See Also

  • error_reporting() — Sets which PHP errors are reported
  • set_error_handler() — Sets a user-defined error handler function
  • restore_error_handler() — Restores the previous error handler function
  • The error level constants

someone at attbi dot com

20 years ago


the idea is never to give out file names, line numbers, and cryptic codes to the user. Use trigger_error() after you used set_error_handler() to register your own callback function which either logs or emails the error codes to you, and echo a simple friendly message to the user.

And turn on a more verbose error handler function when you need to debug your scripts. In my init.php scripts I always have:

if (_DEBUG_) {

    set_error_handler ('debug_error_handler');

}

else {

    set_error_handler ('nice_error_handler');

}


Howard Yeend

13 years ago


trigger_error always reports the line and file that trigger_error was called on. Which isn't very useful.

eg:

main.php:

<?php

include('functions.php');

$x = 'test';

doFunction($x);

?>



functions.php:

<?php

function doFunction($var) {

if(
is_numeric($var)) {

/* do some stuff*/

} else {

trigger_error('var must be numeric');

}

}

?>



will output "Notice: var must be numeric in functions.php on line 6"

whereas "Notice: var must be numeric in main.php on line 4" would be more useful

here's a function to do that:

<?php
function error($message, $level=E_USER_NOTICE) {

$caller = next(debug_backtrace());

trigger_error($message.' in <strong>'.$caller['function'].'</strong> called from <strong>'.$caller['file'].'</strong> on line <strong>'.$caller['line'].'</strong>'."n<br />error handler", $level);

}

?>



So now in our example:

main.php:

<?php

include('functions.php');

$x = 'test';

doFunction($x);

?>



functions.php:

<?php

function doFunction($var) {

    if(
is_numeric($var)) {

        
/* do some stuff*/

   
} else {

        
error('var must be numeric');

    }

}

function

error($message, $level=E_USER_NOTICE) {

   
$caller = next(debug_backtrace());

   
trigger_error($message.' in <strong>'.$caller['function'].'</strong> called from <strong>'.$caller['file'].'</strong> on line <strong>'.$caller['line'].'</strong>'."n<br />error handler", $level);

}

?>



now outputs:

"Notice: var must be numeric in doFunction called from main.php on line 4"


spravce at jednota dot podborany dot cz

3 years ago


Trigger error does not trim  1024+ chars length messages if you use your own error handler

richard at 2006 dot atterer dot net

17 years ago


Beware, trigger_error() is absolutely useless for transporting your own function's error messages in $php_errormsg:

ini_set('track_errors', TRUE);
function x() { trigger_error('MY ERROR'); }
@x();
echo "Error 1: \"$php_errormsg\"\n";
@file_get_contents('/nonexisting');
echo "Error 2: \"$php_errormsg\"\n";

This outputs:

Error 1: ""
Error 2: "failed to open stream: No such file or directory"

This behaviour is consistent with the description of $php_errormsg, which says that the variable will only be available within the scope in which the error occurred. The problem can be worked around with a custom error handler like the one below. However, I'm undecided whether changing the language in this way is good:

function errHandler($errno, $errstr, $errfile, $errline) {
  global $php_errormsg; $php_errormsg = $errstr;
}
set_error_handler('errHandler');


aydin dot kn12 at gmail dot com

8 years ago


If error_type is E_USER_ERROR then trigger_error throw FATAL ERROR and script stopped after this line.

<?php

$msg

= 'This is the test message for echo';trigger_error('Error message', E_USER_ERROR); // Script stopped after this line...echo $msg; // This line does not appear...?>


robert at klugher dot com

19 years ago


This one took me some time ...

When you use trigger_error with your own error handler, the class instances are destroyed (don't know how to say it better, I am not an expert).

So, if you try to call a class function from within the error handler function, you will get 'Call to a member function on a non-object' error, even if this function works perfectly in the rest of your script.

Solution : re-use the xxx = new yyy to re-create the instance in the beginning of your error handler ... and then you can call the class functions you want !


dzn’tM@ter

19 years ago


Some might think that trigger_error is like a throw() or an err.raise construction, and @ works like catch(){} one - in fact it's NOT.

function badgirl(){
    trigger_error("shame on me",E_USER_ERROR);
    return true;
}

$sheis = @badgirl();
echo "You will never see this line - @ only supress message, not a control flow";


PhpMyCoder

12 years ago


For those of you looking to use your own file or line number in the error (possibly using debug_backtrace()) instead of the ones created by trigger_error(), here is a solution:
Create a custom function to handle E_USER_ERRORs that simply outputs the error type and message, while excluding the line number and file trigger_error() reports. You may also configure it to handle user warnings and notices if necessary (I did in the example below).

<?php
function error_handler($level, $message, $file, $line, $context) {
   
//Handle user errors, warnings, and notices ourself
   
if($level === E_USER_ERROR || $level === E_USER_WARNING || $level === E_USER_NOTICE) {
        echo
'<strong>Error:</strong> '.$message;
        return(
true); //And prevent the PHP error handler from continuing
   
}
    return(
false); //Otherwise, use PHP's error handler
}

function

trigger_my_error($message, $level) {
   
//Get the caller of the calling function and details about it
   
$callee = next(debug_backtrace());
   
//Trigger appropriate error
   
trigger_error($message.' in <strong>'.$callee['file'].'</strong> on line <strong>'.$callee['line'].'</strong>', $level);
}
//Use our custom handler
set_error_handler('error_handler');//-------------------------------
//Demo usage:
//-------------------------------
function abc($str) {
    if(!
is_string($str)) {
       
trigger_my_error('abc() expects parameter 1 to be a string', E_USER_ERROR);
    }
}
abc('Hello world!'); //Works
abc(18); //Error: abc() expects parameter 1 to be a string in [FILE].php on line 31
?>

This is a pretty simple concept and I'm sure most of you know this, but for those that don't, let it serve as a good example!


tudor AT iccblue DOT com DOT nospam

13 years ago


It actually turns out - at least on PHP 5.2.6 on XAMPP (Windows) that for the custom error handler, you will need to set $errorType as the first parameter, and only the second parameter as $message, i.e. in reverse order compared to how the manual states it now.

eslindsey at gmail dot com

7 years ago


For those of you wanting one (or more) lines of context on your call to trigger_error, I offer this. Would be nice to use n to get a proper stack trace, but it seems trigger_error escapes it; therefore, I use a comma.

<?php
/**
* Behaves like trigger_error, but appends part of a stack trace to the error
* message. This allows you to see where trigger_error was called from, instead
* of just seeing the file and line number of the call to trigger_error.
*
* @param   error_msg   The designated error message for this error
* @param   error_type  The designated error type for this error (E_USER_*)
* @param   context     Number of stack frames to append, defaults to 1
* @return  FALSE if wrong error_type is specified, TRUE otherwise
*/
function trigger_error_with_context($error_msg, $error_type, $context = 1) {
   
$stack = debug_backtrace();
    for (
$i = 0; $i < $context; $i++)
    {
        if (
false === ($frame = next($stack))
            break;
       
$error_msg .= ", from " . $frame['function'] . ':' . $frame['file'] . ' line ' . $frame['line'];
    }
    return
trigger_error($error_msg, $error_type);
}
?>


phpmanual at allanid dot com

9 months ago


Note that whether or not the script is terminated by this function call, is determined by the error_level.

Eg. E_USER_ERROR will terminate the script while E_USER_NOTICE will not.


mail at dooley dot cjb dot net

19 years ago


i recently began using a custom error handling class. the biggest problem is that, with call time pass by reference deprecated, you can't manipulate the error handler class after assigning at as the error handler (and it appears not to be returned by the set_error_handler method as the old error handler). my goal was to be able to store up all my non-fatal errors and print them at the end of script execution. that way i can use 'trigger_error' (which i actually have wrapped in a static method ErrorHandler::throwException for portability purposes... which is a pain because it always has the same line number information!!) for all kinds of errors, including user input erros. so when i check a user's password, for instance i would trigger a warning that said 'incorrect password'. of course i would only want this to print out the error once the script had completed.

so in my error handler class i have the following in the constructor:

function ErrorHandler()
{
    $this->error_messages  = array();
    error_reporting (E_ALL);
    set_error_handler(array($this,"assignError"));
}

and my assignError method:
//accept the required arguments
function assignError($errno, $errstr, $errfile, $errline)
{
    //get the error string
    $error_message = $errstr;
//if in debug mode, add line number and file info
if(ErrorHandler::DEBUG())
$error_message .= "<br>".basename($errfile).",line: ".$errline;

            switch ($errno)
            {
                //if the error was fatal, then add the error
                //display an error page and exit
                case ErrorHandler::FATAL():
                    $this->setType('Fatal');
                    $this->addError($error_message);
                    Display::errorPage($this->errorMessages());
                    exit(1);
                break;
                //if it was an error message, add a message of
                //type error
                case ErrorHandler::ERROR():
                    $this->setType('Error');
                    $this->addError($error_message);
                break;
                //if it was a warning, add a message of type
                //warning
                case ErrorHandler::WARNING():
                    $this->setType('Warning');
                    $this->addError($error_message);
                break;
                //if it was some other code then display all
                //the error messages that were added
                default:
                    Display::errorRows($this->errorMessages());
                break;
            }
            //return a value so that the script will continue
            //execution
            return 1;
}

the key part there is the 'default' behaviour. i found that if i call trigger_error with anything other than E_USER_ERROR, E_USER_WARNING or E_USER_NOTICE, then error code '2' is passed to the handler method. so when it is time to print all my non-fatal errors, like 'password and confirm password don't match' or something, i call ErrorHandler::printAllErrors()

        function printAllErrors()
        {
            trigger_error("",2);
        }

which leads to the default behaviour in my switch statement in the assignError method above. the only problem with this is that the weird bug 'Problem with method call' that occurs with some static method calls (that one person on the bug lists said was fixed and another said wouldn't be fixed until version 5) also produces error code 2!! i have just taken to suppressing these errors with @, because despite the alledged problem with the method call, the script still seems to execute fine.

iain.


webmaster at paramiliar dot com

15 years ago


We wanted to be able to pass an SQL query to the error handler on our site so we could monitor SQL problems, you cant do this through normal methods so we came up with this bridge script that 100% works

<?phpfunction 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 handlingfunction 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__);?>


mano at easymail dot hu

18 years ago


I am not so familiar with this but I think you can reach some of the functionality of try..catch with this function. I would disagree or correct the previous note. The @ is not the catch, it sets the error_reporting to 0 tempolary but with set_error_handler you can try to imitate some behavior like catch.
I've just made this to try if it possible, I never tried in projects but I think could work in php 4. Actually if you want to have the Trace of the error you need to use php4.3+.
Maybe not many of you will create new scripts in php4 and try to have some features from php5 but in some cases (extending older projects) this could be better error handling.

If this is a wrong approach, waiting for comments, if its not, use it!

<?
function catch($errno, $errstr, $errfile, $errline){
    $GLOBALS['throw'] = $errstr;
    $GLOBALS['throw_info'] = array(
        'Message'=>$errstr
        ,'Code'=>$errno
        ,'Line'=>$errline
        ,'File'=>$errfile
        ,'Trace'=>debug_backtrace()
    );

    }
set_error_handler('catch');

function badgirl(){
    if(true){ //error occure
        trigger_error("BadGirlWithError",E_USER_NOTICE); // as throw with notice
        return; // ...because trigger_error does not stop the function
    }else{
       return true;
    }
}

// Try
$GLOBALS['throw'] = null; // ...try...
$sheis = badgirl(); //could be @badgirl, display_errors is something else, this just the handling
// ..try
if($GLOBALS['throw']){  // This actually catch re-throws too...
    switch($GLOBALS['throw']){ // Catch
        case 'GoodGirlException':
            die('No bad girl today!');
        break;
        case 'BadGirlWithError':
            die('Bad girl has some error');
        break;
        default:
            return; // or you can make another trigger_error and re-throw another 'exception' or some other action
    }
}
echo "You will never see this line - @ only supress message, not a control flow";
echo "Wrong! You could see this:)";

?>

.mano


sl0th at r00thell dot ath dot cx

20 years ago


Well this is a good way on debuging your php scripts, but i wouldn't feel
too comfortable by giving out my web servers structure.
Notice that what helps you finding and isolating errors in your php helps also a potential attacker.
Or maybe i am just paranoid, but its worth mention it.

ceo at l-i-e dot com

20 years ago


You should be using set_error_handler (possibly in conjuction with error_log and/or trigger_error) if you want FILE and LINE number information.
You don't need macros for this.

Исключения

Содержание

  • Наследование исключений

В PHP реализована модель исключений, аналогичная тем, что используются в других языках программирования.
Исключение в PHP может быть выброшено (throw) и поймано (catch).
Код может быть заключён в блок try, чтобы облегчить обработку потенциальных исключений.
У каждого блока try должен быть как минимум один соответствующий блок catch или finally.

Если выброшено исключение, а в текущей области видимости функции нет блока catch,
исключение будет «подниматься» по стеку вызовов к вызывающей функции, пока не найдёт подходящий блок catch.
Все блоки finally, которые встретятся на этом пути, будут выполнены.
Если стек вызовов разворачивается до глобальной области видимости, не встречая подходящего блока catch,
программа завершается с неисправимой ошибкой, если не был установлен глобальный обработчик исключений.

Выброшенный объект должен наследовать (instanceof) интерфейс Throwable.
Попытка выбросить объект, который таковым не является, приведёт к неисправимой ошибке PHP.

Начиная с PHP 8.0.0, ключевое слово throw является выражением и может быть использовано
в любом контексте выражения. В предыдущих версиях оно было утверждением
и должно было располагаться в отдельной строке.

catch

Блок catch определяет, как реагировать на выброшенное исключение.
Блок catch определяет один или несколько типов исключений или ошибок, которые он может обработать,
и, по желанию, переменную, которой можно присвоить исключение
(указание переменной было обязательно до версии PHP 8.0.0).
Первый блок catch, с которым столкнётся выброшенное исключение или ошибка
и соответствует типу выброшенного объекта, обработает объект.

Несколько блоков catch могут быть использованы для перехвата различных классов исключений.
Нормальное выполнение (когда исключение не выброшено в блоке try)
будет продолжаться после последнего блока catch, определённого в последовательности.
Исключения могут быть выброшены (throw) (или повторно выброшены) внутри блока catch.
В противном случае выполнение будет продолжено после блока catch, который был вызван.

При возникновении исключения, код, следующий за утверждением, не будет выполнен,
а PHP попытается найти первый подходящий блок catch.
Если исключение не поймано, будет выдана неисправимая ошибка PHP
с сообщением «Uncaught Exception ...«,
если только обработчик не был определён с помощью функции set_exception_handler().

Начиная с версии PHP 7.1.0, в блоке catch можно указывать несколько исключений,
используя символ |. Это полезно, когда разные исключения
из разных иерархий классов обрабатываются одинаково.

Начиная с версии PHP 8.0.0, имя переменной для пойманного исключения является необязательным.
Если оно не указано, блок catch будет выполнен,
но не будет иметь доступа к выброшенному объекту.

finally

Блок finally также может быть указан после или вместо блоков catch.
Код в блоке finally всегда будет выполняться после блоков try и catch,
независимо от того, было ли выброшено исключение
и до возобновления нормального выполнения.

Одно из заметных взаимодействий происходит между блоком finally и оператором return.
Если оператор return встречается внутри блоков try или catch, блок finally
всё равно будет выполнен. Более того, оператор return выполнится, когда встретится,
но результат будет возвращён после выполнения блока finally.
Кроме того, если блок finally также содержит оператор return,
возвращается значение из блока finally.

Глобальный обработчик исключений

Если исключению разрешено распространяться на глобальную область видимости,
оно может быть перехвачено глобальным обработчиком исключений, если он установлен.
Функция set_exception_handler() может задать функцию,
которая будет вызвана вместо блока catch, если не будет вызван никакой другой блок.
Эффект по сути такой же, как если бы вся программа была обёрнута в блок trycatch
с этой функцией в качестве catch.

Примечания

Замечание:

Внутренние функции PHP в основном используют отчёт об ошибках,
только современные объектно-ориентированные модули используют исключения.
Однако ошибки можно легко перевести в исключения с помощью класса ErrorException.
Однако эта техника работает только с исправляемыми ошибками.

Пример #1 Преобразование отчётов об ошибках в исключения


<?php
function exceptions_error_handler($severity, $message, $filename, $lineno) {
throw new
ErrorException($message, 0, $severity, $filename, $lineno);
}
set_error_handler('exceptions_error_handler');
?>

Примеры

Пример #2 Выбрасывание исключения


<?php
function inverse($x) {
if (!
$x) {
throw new
Exception('Деление на ноль.');
}
return
1/$x;
}

try {
echo

inverse(5) . "n";
echo
inverse(0) . "n";
} catch (
Exception $e) {
echo
'Выброшено исключение: ', $e->getMessage(), "n";
}
// Продолжение выполнения
echo "Привет, мирn";
?>

Результат выполнения данного примера:

0.2
Выброшено исключение: Деление на ноль.
Привет, мир

Пример #3 Обработка исключений с помощью блока finally


<?php
function inverse($x) {
if (!
$x) {
throw new
Exception('Деление на ноль.');
}
return
1/$x;
}

try {
echo

inverse(5) . "n";
} catch (
Exception $e) {
echo
'Поймано исключение: ', $e->getMessage(), "n";
} finally {
echo
"Первый блок finally.n";
}

try {
echo

inverse(0) . "n";
} catch (
Exception $e) {
echo
'Поймано исключение: ', $e->getMessage(), "n";
} finally {
echo
"Второй блок finally.n";
}
// Продолжение нормального выполнения
echo "Привет, мирn";
?>

Результат выполнения данного примера:

0.2
Первый блок finally.
Поймано исключение: Деление на ноль.
Второй блок finally.
Привет, мир

Пример #4 Взаимодействие между блоками finally и return


<?phpfunction test() {
try {
throw new
Exception('foo');
} catch (
Exception $e) {
return
'catch';
} finally {
return
'finally';
}
}

echo

test();
?>

Результат выполнения данного примера:

Пример #5 Вложенные исключения


<?phpclass MyException extends Exception { }

class

Test {
public function
testing() {
try {
try {
throw new
MyException('foo!');
} catch (
MyException $e) {
// повторный выброс исключения
throw $e;
}
} catch (
Exception $e) {
var_dump($e->getMessage());
}
}
}
$foo = new Test;
$foo->testing();?>

Результат выполнения данного примера:

Пример #6 Обработка нескольких исключений в одном блоке catch


<?phpclass MyException extends Exception { }

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();?>

Результат выполнения данного примера:

Пример #7 Пример блока catch без указания переменной

Допустимо начиная с PHP 8.0.0


<?phpclass SpecificException extends Exception {}

function

test() {
throw new
SpecificException('Ой!');
}

try {

test();
} catch (
SpecificException) {
print
"Было поймано исключение SpecificException, но нам безразлично, что у него внутри.";
}
?>

Пример #8 Throw как выражение

Допустимо начиная с PHP 8.0.0


<?phpfunction test() {
do_something_risky() or throw new Exception('Всё сломалось');
}

try {

test();
} catch (
Exception $e) {
print
$e->getMessage();
}
?>

ask at nilpo dot com

14 years ago


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.

<?php
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;                             // Unknownpublic 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:

<?php
class TestException extends CustomException {}
?>

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

<?php
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

'<pre>' . exceptionTest() . '</pre>';
?>

Here's a sample output:

Caught TestException ('Unknown TestException')
TestException 'Unknown TestException' in C:xampphtdocsCustomExceptionCustomException.php(31)
#0 C:xampphtdocsCustomExceptionExceptionTest.php(19): CustomException->__construct()
#1 C:xampphtdocsCustomExceptionExceptionTest.php(43): exceptionTest()
#2 {main}


Johan

12 years ago


Custom error handling on entire pages can avoid half rendered pages for the users:

<?php
ob_start
();
try {
   
/*contains all page logic
    and throws error if needed*/
   
...
} catch (
Exception $e) {
 
ob_end_clean();
 
displayErrorPage($e->getMessage());
}
?>


christof+php[AT]insypro.com

5 years ago


In case your E_WARNING type of errors aren't catchable with try/catch you can change them to another type of error like this:

<?php
    set_error_handler
(function($errno, $errstr, $errfile, $errline){
            if(
$errno === E_WARNING){
               
// make it more serious than a warning so it can be caught
               
trigger_error($errstr, E_ERROR);
                return
true;
            } else {
               
// fallback to default php error handler
               
return false;
            }
    });

    try {

// code that might result in a E_WARNING
   
} catch(Exception $e){
           
// code to handle the E_WARNING (it's actually changed to E_ERROR at this point)
   
} finally {
           
restore_error_handler();
    }
?>


lscorionjs at gmail dot com

4 months ago


<?phptry {
 
$str = 'hi';
  throw new
Exception();
} catch (
Exception) {
 
var_dump($str);
} finally {
 
var_dump($str);
}
?>

Output:
string(2) "hi"
string(2) "hi"

Shot (Piotr Szotkowski)

14 years ago


‘Normal execution (when no exception is thrown within the try block, *or when a catch matching the thrown exception’s class is not present*) will continue after that last catch block defined in sequence.’

‘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().’

These two sentences seem a bit contradicting about what happens ‘when a catch matching the thrown exception’s class is not present’ (and the second sentence is actually correct).


Simo

8 years ago


#3 is not a good example. inverse("0a") would not be caught since (bool) "0a" returns true, yet 1/"0a" casts the string to integer zero and attempts to perform the calculation.

daviddlowe dot flimm at gmail dot com

5 years ago


Starting in PHP 7, the classes Exception and Error both implement the Throwable interface. This means, if you want to catch both Error instances and Exception instances, you should catch Throwable objects, like this:

<?phptry {
    throw new
Error( "foobar" );
   
// or:
    // throw new Exception( "foobar" );
}
catch (
Throwable $e) {
   
var_export( $e );
}
?>


Edu

9 years ago


The "finally" block can change the exception that has been throw by the catch block.

<?php
try{
        try {
                throw new
Exception("Hello");
        } catch(
Exception $e) {
                echo
$e->getMessage()." catch inn";
                throw
$e;
        } finally {
                echo
$e->getMessage()." finally n";
                throw new
Exception("Bye");
        }
} catch (
Exception $e) {
        echo
$e->getMessage()." catch outn";
}
?>

The output is:

Hello catch in
Hello finally
Bye catch out


mlaopane at gmail dot com

5 years ago


<?php/**
* You can catch exceptions thrown in a deep level function
*/
function employee()
{
    throw new
Exception("I am just an employee !");
}

function

manager()
{
   
employee();
}

function

boss()
{
    try {
       
manager();
    } catch (
Exception $e) {
        echo
$e->getMessage();
    }
}
boss(); // output: "I am just an employee !"

telefoontoestel at nospam dot org

8 years ago


When using finally keep in mind that when a exit/die statement is used in the catch block it will NOT go through the finally block.

<?php
try {
    echo
"try block<br />";
    throw new
Exception("test");
} catch (
Exception $ex) {
    echo
"catch block<br />";
} finally {
    echo
"finally block<br />";
}
// try block
// catch block
// finally block
?>

<?php
try {
    echo
"try block<br />";
    throw new
Exception("test");
} catch (
Exception $ex) {
    echo
"catch block<br />";
    exit(
1);
} finally {
    echo
"finally block<br />";
}
// try block
// catch block
?>


Tom Polomsk

8 years ago


Contrary to the documentation it is possible in PHP 5.5 and higher use only try-finally blocks without any catch block.

Sawsan

11 years ago


the following is an example of a re-thrown exception and the using of getPrevious function:

<?php

$name

= "Name";//check if the name contains only letters, and does not contain the word nametry
   {
   try
     {
      if (
preg_match('/[^a-z]/i', $name))
       {
           throw new
Exception("$name contains character other than a-z A-Z");
       }  
       if(
strpos(strtolower($name), 'name') !== FALSE)
       {
          throw new
Exception("$name contains the word name");
       }
       echo
"The Name is valid";
     }
   catch(
Exception $e)
     {
     throw new
Exception("insert name again",0,$e);
     }
   }

catch (

Exception $e)
   {
   if (
$e->getPrevious())
   {
    echo
"The Previous Exception is: ".$e->getPrevious()->getMessage()."<br/>";
   }
   echo
"The Exception is: ".$e->getMessage()."<br/>";
   }
?>


ilia-yats at ukr dot net

5 months ago


Note some undocumented details about exceptions thrown from 'finally' blocks.

When exception is thrown from 'finally' block, it overrides the original not-caught (or re-thrown) exception. So the behavior is similar to 'return': value returned from 'finally' overrides the one returned earlier. And the original exception is automatically appended to the exceptions chain, i.e. becomes 'previous' for the new one. Example:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } finally {
        throw new
Exception('thrown from finally');
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// thrown from try
?>

Example with re-throwing:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } catch (
Exception $e) {
        throw new
Exception('thrown from catch');
    } finally {
        throw new
Exception('thrown from finally');
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// thrown from catch
?>

The same happens even if explicitly pass null as previous exception:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } finally {
        throw new
Exception('thrown from finally', null, null);
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// thrown from try
?>

Also it is possible to pass previous exception explicitly, the 'original' one will be still appended to the chain, e.g.:
<?php
try {
    try {
        throw new
Exception('thrown from try');
    } finally {
        throw new
Exception(
           
'thrown from finally',
           
null,
            new
Exception('Explicitly set previous!')
        );
    }
} catch(
Exception $e) {
    echo
$e->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getMessage();
    echo
PHP_EOL;
    echo
$e->getPrevious()->getPrevious()->getMessage();
}
// will output:
// thrown from finally
// Explicitly set previous!
// thrown from try
?>

This seems to be true for versions 5.6-8.2.


Daan

1 year ago


I would like to emphasise that you can not rethrow an Exception inside a catch-block and expect that the next catch-block will handle it.

<?php try {
    throw new
RuntimeException('error');           
} catch (
RuntimeException $e) {
    throw
$e;
} catch (
Exception $e) {
   
// this will not be executed[
}
?>


Хотя PHP уже давно поддерживает обработку исключений, однако, по сравнению с Java эта поддержка была довольно слабой

Первоначальная поддержка обработки исключений была введена в язык с 5 версии PHP, с двумя простыми встроенными классами исключений — Exception и ErrorException, с поддержкой дополнительных классов через SPL. Идея этого поста состоит в том, чтобы представить читателям современные возможности обработки исключений PHP. 

Новый интерфейс

Хотя PHP 7 предоставляет классы Error и Exception, давайте сначала затронем интерфейс Throwable . И Error и Exception классы реализуют Throwable интерфейс — это основа для любого объекта , который может быть брошен с помощью оператора throw. Единственное, что он не может быть реализован непосредственно в классах пользовательского пространства, только через расширение класса Exception. Кроме того, он обеспечивает единую точку для отлова обоих типов ошибок в одном выражении:

<?php

try {
// ваш код
} catch (Throwable $e) {
echo 'Очень хороший способ отловить исключения и ошибки';
}

Список доступных встроенных классов исключений начиная с PHP 7.4:

  • Exception
  • ErrorException
  • Error
  • ArgumentCountError
  • ArithmeticError
  • AssertionError
  • DivisionByZeroError
  • CompileError
  • ParseError
  • TypeError

Дополнительные классы исключений можно найти в стандартной библиотеке PHP . И наиболее заметным из расширений JSON является класс JsonException.

THROWABLE

Интерфейс Throwable  PHP 7:

interface Throwable
{
public function getMessage(): string; // Error reason
public function getCode(): int; // Error code
public function getFile(): string; // Error begin file
public function getLine(): int; // Error begin line
public function getTrace(): array; // Return stack trace as array like debug_backtrace()
public function getTraceAsString(): string; // Return stack trace as string
public function getPrevious(): Throwable; // Return previous `Trowable`
public function __toString(): string; // Convert into string
}

Вот иерархия Throwable:

interface Throwable
|- Error implements Throwable
|- ArithmeticError extends Error
|- DivisionByZeroError extends ArithmeticError
|- AssertionError extends Error
|- ParseError extends Error
|- TypeError extends Error
|- ArgumentCountError extends TypeError
|- Exception implements Throwable
|- ClosedGeneratorException extends Exception
|- DOMException extends Exception
|- ErrorException extends Exception
|- IntlException extends Exception
|- LogicException extends Exception
|- BadFunctionCallException extends LogicException
|- BadMethodCallException extends BadFunctionCallException
|- DomainException extends LogicException
|- InvalidArgumentException extends LogicException
|- LengthException extends LogicException
|- OutOfRangeException extends LogicException
|- PharException extends Exception
|- ReflectionException extends Exception
|- RuntimeException extends Exception
|- OutOfBoundsException extends RuntimeException
|- OverflowException extends RuntimeException
|- PDOException extends RuntimeException
|- RangeException extends RuntimeException
|- UnderflowException extends RuntimeException
|- UnexpectedValueException extends RuntimeException

Ошибка, почему?

В предыдущих версиях PHP ошибки обрабатывались совершенно иначе, чем исключения. Если возникала ошибка, то пока она не была фатальной, она могла быть обработана пользовательской функцией.

Проблема заключалась в том, что было несколько фатальных ошибок, которые не могли быть обработаны определяемым пользователем обработчиком ошибок. Это означало, что вы не могли корректно обрабатывать фатальные ошибки в PHP. Было несколько побочных эффектов, которые были проблематичными, такие как потеря контекста времени выполнения, деструкторы не вызывались, да и вообще иметь дело с ними было неудобно. В PHP 7 фатальные ошибки теперь являются исключениями, и мы можем легко их обработать. Фатальные ошибки приводят к возникновению исключений. Вам необходимо обрабатывать нефатальные ошибки с помощью функции обработки ошибок.

Вот пример ловли фатальной ошибки в PHP 7.1. Обратите внимание, что нефатальная ошибка не обнаружена.

<?php 

try {
// будет генерировать уведомление, которое не будет поймано
echo $someNotSetVariable;
// фатальная ошибка, которая сейчас на самом деле ловится
someNoneExistentFunction();
} catch (Error $e) {
echo "Error caught: " . $e->getMessage();
}

Этот скрипт выведет сообщение об ошибке при попытке доступа к недопустимой переменной. Попытка вызвать функцию, которая не существует, приведет к фатальной ошибке в более ранних версиях PHP, но в PHP 7.1 вы можете ее перехватить. Вот вывод для скрипта:

Notice: Undefined variable: someNotSetVariable on line 3
Error caught: Call to undefined function someNoneExistentFunction()

Константы ошибок

В PHP много констант, которые используются в отношении ошибок. Эти константы используются при настройке PHP для скрытия или отображения ошибок определенных классов.

Вот некоторые из наиболее часто встречающихся кодов ошибок:

  • E_DEPRECATED — интерпретатор сгенерирует этот тип предупреждений, если вы используете устаревшую языковую функцию. Сценарий обязательно продолжит работать без ошибок.
  • E_STRICT — аналогично E_DEPRECATED, — указывает на то, что вы используете языковую функцию, которая не является стандартной в настоящее время и может не работать в будущем. Сценарий будет продолжать работать без каких-либо ошибок.
  • E_PARSE — ваш синтаксис не может быть проанализирован, поэтому ваш скрипт не запустится. Выполнение скрипта даже не запустится.
  • E_NOTICE — движок просто выведет информационное сообщение. Выполнение скрипта не прервется, и ни одна из ошибок не будет выдана.
  • E_ERROR — скрипт не может продолжить работу, и завершится. Выдает ошибки, а как они будут обрабатываться, зависит от обработчика ошибок.
  • E_RECOVERABLE_ERROR — указывает на то, что, возможно, произошла опасная ошибка, и движок работает в нестабильном состоянии. Дальнейшее выполнение зависит от обработчика ошибок, и ошибка обязательно будет выдана.

Полный список констант можно найти в руководстве по PHP.

Функция обработчика ошибок

Функция set_error_handler() используется, чтобы сообщить PHP как обрабатывать стандартные ошибки, которые не являются экземплярами класса исключений Error. Вы не можете использовать функцию обработчика ошибок для фатальных ошибок. Исключения ошибок должны обрабатываться с помощью операторов try/catch. set_error_handler() принимает callback функцию в качестве своего параметра. Callback-функции в PHP могут быть заданы двумя способами: либо строкой, обозначающей имя функции, либо передачей массива, который содержит объект и имя метода (именно в этом порядке). Вы можете указать защищенные и приватные методы для callable в объекте. Вы также можете передать значение null, чтобы указать PHP вернуться к использованию стандартного механизма обработки ошибок. Если ваш обработчик ошибок не завершает программу и возвращает результат, ваш сценарий будет продолжать выполняться со строки, следующей за той, где произошла ошибка.

PHP передает параметры в вашу функцию обработчика ошибок. Вы можете опционально объявить их в сигнатуре функции, если хотите использовать их в своей функции.

Вот пример:

<?php

function myCustomErrorHandler(int $errNo, string $errMsg, string $file, int $line) {
echo "Ух ты, мой обработчик ошибок получил #[$errNo] в [$file] на [$line]: [$errMsg]";
}

set_error_handler('myCustomErrorHandler');

try {
why;
} catch (Throwable $e) {
echo 'И моя ошибка: ' . $e->getMessage();
}

Если вы запустите этот код в PHP-консоли php -a, вы должны получить похожий вывод:

Error #[2] occurred in [php shell code] at line [3]: [Use of undefined constant why - assumed 'why' (this will throw an Error in a future version of PHP)]

Самые известные PHP библиотеки , которые делают обширное использование РНР set_error_handler() и могут сделать хорошие представления исключений и ошибок являются whoops,  и Symony Debug, ErrorHandler компоненты. Я смело рекомендую использовать один из них. Если не собираетесь их использовать в своем проекте, то вы всегда можете черпать вдохновение из их кода. В то время как компонент Debug широко используется в экосистеме Symfony, Whoops остается библиотекой выбора для фреймворка Laravel . 

Для подробного и расширенного использования, пожалуйста, обратитесь к руководству по PHP для обработчика ошибок.

Отображение или подавление нефатальной ошибки

Когда ваше приложение выходит в продакшн, логично, что вы хотите скрыть все системные сообщения об ошибках во время работы, и ваш код должен работать без генерации предупреждений или сообщений. Если вы собираетесь показать сообщение об ошибке, убедитесь, что оно сгенерировано и не содержит информации, которая может помочь злоумышленнику проникнуть в вашу систему.

В вашей среде разработки вы хотите, чтобы все ошибки отображались, чтобы вы могли исправить все проблемы, с которыми они связаны, но в процессе работы вы хотите подавить любые системные сообщения, отправляемые пользователю.

Для этого вам нужно настроить PHP, используя следующие параметры в вашем файле php.ini:

  • display_errors – может быть установлен в false для подавления сообщений
  • log_errors – может использоваться для хранения сообщений об ошибках в файлах журнала
  • error_reporting – можно настроить, какие ошибки вызывают отчет

Лучше всего корректно обрабатывать ошибки в вашем приложении. В производственном процессе вы должны скорее регистрировать необработанные ошибки, чем разрешать их отображение пользователю. Функция error_log() может использоваться для отправки сообщения одной из определенных процедур обработки ошибок. Вы также можете использовать функцию error_log() для отправки электронных писем, но лично вы бы предпочли использовать хорошее решение для регистрации ошибок и получения уведомлений при возникновении ошибок, например Sentry или Rollbar .

Существует вещь, называемая оператором контроля ошибок ( @ ), который по своей сути может игнорировать и подавлять ошибки. Использование очень простое — просто добавьте любое выражение PHP с символом «собаки», и сгенерированная ошибка будет проигнорирована. Хотя использование этого оператора может показаться интересным, я призываю вас не делать этого. Мне нравится называть это живым пережитком прошлого.

Больше информации для всех функций, связанных с ошибками PHP, можно найти в руководстве.

Исключения (Exceptions)

Исключения являются основной частью объектно-ориентированного программирования и впервые были представлены в PHP 5.0. Исключением является состояние программы, которое требует специальной обработки, поскольку оно не выполняется ожидаемым образом. Вы можете использовать исключение, чтобы изменить поток вашей программы, например, чтобы прекратить что-либо делать, если некоторые предварительные условия не выполняются.

Исключение будет возникать в стеке вызовов, если вы его не перехватите. Давайте посмотрим на простой пример:

try {
print "это наш блок попыток n";
throw new Exception();
} catch (Exception $e) {
print "что-то пошло не так, есть улов!";
} finally {
print "эта часть всегда выполняется";
}

PHP включает в себя несколько стандартных типов исключений, а стандартная библиотека PHP (SPL) включает в себя еще несколько. Хотя вам не нужно использовать эти исключения, это означает, что вы можете использовать более детальное обнаружение ошибок и отчеты. Классы Exception и Error реализуют интерфейс Throwable и, как и любые другие классы, могут быть расширены. Это позволяет вам создавать гибкие иерархии ошибок и адаптировать обработку исключений. Только класс, который реализует класс Throwable, может использоваться с ключевым словом throw. Другими словами, вы не можете объявить свой собственный базовый класс и затем выбросить его как исключение.

Надежный код может встретить ошибку и справиться с ней. Разумная обработка исключений повышает безопасность вашего приложения и облегчает ведение журнала и отладку. Управление ошибками в вашем приложении также позволит вам предложить своим пользователям лучший опыт. В этом разделе мы рассмотрим, как отлавливать и обрабатывать ошибки, возникающие в вашем коде.

Ловля исключений

Вы должны использовать try/catch структуру:

<?php

class MyCustomException extends Exception { }

function throwMyCustomException() {
throw new MyCustomException('Здесь что-то не так.');
}

try {
throwMyCustomException();
} catch (MyCustomException $e) {
echo "Ваше пользовательское исключение поймано";
echo $e->getMessage();
} catch (Exception $e) {
echo "Стандартное исключение PHP";
}

Как видите, есть два предложения catch. Исключения будут сопоставляться с предложениями сверху вниз, пока тип исключения не будет соответствовать предложению catch. Эта очень простая функция throwMyCustomException() генерирует исключение MyCustomException, и мы ожидаем, что оно будет перехвачено в первом блоке. Любые другие исключения, которые произойдут, будут перехвачены вторым блоком. Здесь мы вызываем метод getMessage() из базового класса Exception. Вы можете найти больше информации о дополнительном методе в Exception PHP docs.

Кроме того, можно указать несколько исключений, разделяя их трубой ( | ).

Давайте посмотрим на другой пример:

<?php

class MyCustomException extends Exception { }
class MyAnotherCustomException extends Exception { }

try {
throw new MyAnotherCustomException;
} catch (MyCustomException | MyAnotherCustomException $e) {
echo "Caught : " . get_class($e);
}

Этот очень простой блок catch будет перехватывать исключения типа MyCustomException и MyAnotherCustomException.

Немного более продвинутый сценарий:

// exceptions.php
use SymfonyComponentHttpKernelExceptionNotFoundHttpException;

try {
throw new NotFoundHttpException();
} catch (Exception $e) {
echo 1;
} catch (NotFoundHttpException $e) {
echo 2;
} catch (Exception $e) {
echo 3;
} finally {
echo 4;
}

Это ваш окончательный ответ?

В PHP 5.5 и более поздних, блок finally также может быть указан после или вместо блоков catch. Код внутри блока finally всегда будет выполняться после блоков try и catch независимо от того, было ли выброшено исключение, и до возобновления нормального выполнения. Одним из распространенных применений блока finally является закрытие соединения с базой данных, но, наконец, его можно использовать везде, где вы хотите, чтобы код всегда выполнялся.

<?php

class MyCustomException extends Exception { }

function throwMyCustomException() {
throw new MyCustomException('Здесь что-то не так');
}

try {
throwMyCustomException();
} catch (MyCustomException $e) {
echo "Ваше пользовательское исключение поймано ";
echo $e->getMessage();
} catch (Exception $e) {
echo "Стандартное исключение PHP";
} finally {
echo "Я всегда тут";
}

Вот хороший пример того, как работают операторы PHP catch/finally:

<?php

try {
try {
echo 'a-';
throw new exception();
echo 'b-';
} catch (Exception $e) {
echo 'пойманный-';
throw $e;
} finally {
echo 'завершенный-';
}
} catch (Exception $e) {
echo 'конец-';
}

Функция обработчика исключений

Любое исключение, которое не было обнаружено, приводит к фатальной ошибке. Если вы хотите изящно реагировать на исключения, которые не перехватываются в блоках перехвата, вам нужно установить функцию в качестве обработчика исключений по умолчанию.

Для этого вы используете функцию set_exception_handler() , которая принимает вызываемый элемент в качестве параметра. Ваш сценарий завершится после того, как вызов будет выполнен.

Функция restore_exception_handler() вернет обработчик исключений к его предыдущему значению.

<?php

class MyCustomException extends Exception { }

function exception_handler($exception) {
echo "Uncaught exception: " , $exception->getMessage(), "n";
}

set_exception_handler('exception_handler');

try {
throw new Exception('Uncaught Exception');
} catch (MyCustomException $e) {
echo "Ваше пользовательское исключение поймано ";
echo $e->getMessage();
} finally {
echo "Я всегда тут";
}

print "Не выполнено";

Здесь простая функция exception_handler будет выполняться после блока finally, когда ни один из типов исключений не был сопоставлен. Последний вывод никогда не будет выполнен.

Для получения дополнительной информации обратитесь к документации PHP. 

Старый добрый «T_PAAMAYIM_NEKUDOTAYIM»

Вероятно, это было самое известное сообщение об ошибке PHP. В последние годы было много споров по этому поводу. Вы можете прочитать больше в отличном сообщении в блоге от Фила Осетра .  

Сегодня я с гордостью могу сказать, что если вы запустите этот код с PHP 7, то сообщение о T_PAAMAYIM_NEKUDOTAYIM больше не будет:

<?php

class foo
{
static $bar = 'baz';
}

var_dump('foo'::$bar);

// Output PHP < 7.0:
// PHP Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM) in php shell code on line 1
// Output PHP > 7.0:
// string(3) "baz"
?>

В заключении

Со времени первого внедрения обработки исключений в PHP прошло много лет, пока мы не получили гораздо более надежную и зрелую обработку исключений, чем в Java. Обработка ошибок в PHP 7 получила много внимания, что делает его хорошим, открывая пространство для будущих улучшений, если мы действительно с сегодняшней точки зрения нуждаемся в них.

PHP5 Обработка ошибок



Обработка ошибок по умолчанию в PHP очень проста. Сообщение об ошибке с именем файла, строка число и сообщение, описывающее ошибку, отправляется в браузер.


При создании скриптов и веб-приложений, обработка ошибок, является важной
частью. Если коду не хватает кода проверки ошибок, программа может выглядеть
непрофессионально и Вы можете быть открыты для рисков безопасности.

Учебник содержит несколько из наиболее распространенных методов проверки ошибок в PHP.

Вы узнаете различные методы обработки ошибок:

  • Простое заявление это()
  • Пользовательские ошибки и триггеры ошибок
  • Отчеты об ошибках

PHP Основная обработка ошибок

В первом примере показан простой скрипт, открывающий текстовый файл: использование функции это()

Пример

<?php
$file=fopen(«welcome.txt»,»r»);
?>

Если файл не существует, Вы можете получить ошибку, как эта:

Внимание: fopen(welcome.txt) [function.fopen]: не удалось открыть поток:
Нет такого файла или каталога в C:webfoldertest.php на линии 2

Чтобы запретить пользователю получать сообщение об ошибке, подобное приведенному примеру выше, мы проверяем
файл, существует ли он до того, как мы попытаемся получить к нему доступ:

Пример

<?php
if(!file_exists(«welcome.txt»)) {
  die(«Файл не найден»);
}
else {
  $file=fopen(«welcome.txt»,»r»);
}
?>

Теперь, если файл не существует вы получите ошибку, как эта:

Файл не найден

Приведенный ниже код более эффективен, чем предыдущий код, поскольку он использует простой механизм обработки ошибок для остановки сценария после ошибки.

Тем не менее, остановить просто сценарий не всегда правильный путь. Рассмотрим альтернативные функции PHP для обработки ошибок.


PHP Создание пользовательского обработчика ошибок

Создать пользовательский обработчик ошибок довольно просто. Создаем специальную функцию, которая может быть вызвана при возникновении ошибки в PHP.

Эта функция должна быть способна обрабатывать, как минимум два параметра (уровень ошибки и сообщение об ошибке),
но можно принимать до пяти параметров (дополнительно: файл, номер строки и контекст ошибки):

Синтаксис

error_function(error_level,error_message,
error_file,error_line,error_context)

Параметр Описание
error_level Необходимо. Указывает уровень отчета об ошибках для пользовательской ошибки.
Должно быть числовое значение. См. таблицу ниже для возможных уровней отчета об ошибках
error_message Необходимо. Указывает сообщение об ошибке определяемая пользователем
error_file Необязательно. Задает имя файла, в котором произошла ошибка
error_line Необязательно. Указывает номер строки, в которой произошла ошибка
error_context Необязательно. Задает массив, содержащий все переменные и их значения, используемые при возникновении ошибки

PHP Уровни отчетов об ошибках

Эти уровни отчетов об ошибках, являются различными типами ошибок, для которых может использоваться определяемый пользователем обработчик ошибок:

Значение Констант Описание
2 E_WARNING Неустранимые ошибки выполнения. Выполнение скрипта не останавливается
8 E_NOTICE Уведомления среды выполнения. Сценарий нашел что-то, что могло бы быть ошибкой, но могло бы также произойти при запуске сценария, как обычно
256 E_USER_ERROR Неустранимая ошибка пользователя. Это похоже на набор E_ERROR установленный программистом с помощью функции PHP trigger_error()
512 E_USER_WARNING Неустранимое пользовательское предупреждение. Это похоже на набор E_WARNING установленный программистом с помощью функции PHP trigger_error()
1024 E_USER_NOTICE Автоматическое уведомление пользователя. Это похоже на набор E_NOTICE устанавливается программистом с помощью функции PHP trigger_error()
4096 E_RECOVERABLE_ERROR Перехватываемая неустранимая ошибка. Это похоже на набор E_ERROR но может быть перехватана пользователем, определенной обработкой (смотреть также set_error_handler())
8191 E_ALL Все ошибки и предупреждение (E_STRICT становится частью E_ALL в PHP 5.4)

Теперь давайте создадим функцию для обработки ошибок:

Пример

function customError($errno, $errstr) {
  echo «<b>Ошибка:</b> [$errno] $errstr<br>»;
  echo «Конечный Script»;
  die();
}

Приведенный выше код, является простой функцией обработки ошибок. Когда он срабатывает, он получает код ошибки и сообщение об ошибке.
Затем выводится уровень ошибки и сообщение и завершается сценарий.

Теперь, когда Вы создали функцию обработки ошибок, Вы должны решить, когда она должно сработать.


PHP Установить обработчик ошибок

Обработчик ошибок по умолчанию для PHP является встроенным обработчиком ошибок.
Мы собираемся сделать функцию над обработчиком ошибок по умолчанию на время скрипта.

Можно изменить обработчик ошибок для применения только к некоторым ошибкам, таким образом,
сценарий может обрабатывать различные ошибки по-разному.
Однако, в этом примере мы будем использовать наш пользовательский обработчик ошибок для всех ошибок:

set_error_handler(«customError»);

Поскольку мы хотим, чтобы наша пользовательская функция обрабатывала все ошибки, set_error_handler()
требуется только один параметр, второй параметр может быть добавлен, чтобы указать уровень ошибки.

Тестирование обработчика ошибок при попытке вывести несуществующую переменную:

Пример

<?php
//функция обработчика ошибок
function customError($errno, $errstr) {
  echo «<b>Ошибка:</b> [$errno] $errstr»;
}

//установить обработчик ошибок
set_error_handler(«customError»);

//Вызов ошибки
echo($test);
?>

Выходные данные приведенного выше кода должны быть примерно такими:

Ошибка: [8] Неопределенна переменная: test


PHP Вызвать ошибку

В скрипте, где пользователи могут вводить данные, полезно инициировать ошибки, когда происходит незаконный ввод.
В PHP это делается с помощью функции trigger_error().

В этом примере возникает ошибка, если $test переменная больше, чем 1:

Пример

<?php
$test=2;
if ($test>=1)
{
 
trigger_error(«Значение должно быть 1 или ниже»);
}
?>

Выходные данные приведенного выше кода должны быть примерно такими:

Заметьте: Значение должно быть 1 или ниже
в C:webfoldertest.php на линии 6

Ошибка может быть вызвана в любом месте сценария и путем добавления
второй параметр, Вы можете указать, какой уровень ошибки срабатывает.

Возможные типы ошибок:

  • E_USER_ERROR — Неустранимая пользовательская ошибка выполнения. Ошибки, из которых невозможно восстановить. Выполнение скрипта прекращается
  • E_USER_WARNING — Непоправимое пользовательское предупреждение во время выполнения. Выполнение скрипта не останавливается
  • E_USER_NOTICE — Невыполнение. Уведомление о времени выполнения, созданное пользователем. Сценарий нашел что-то, что могло бы быть ошибкой, но могло бы также произойти при запуске сценария

В этом примере E_USER_WARNING происходит, если переменная $test больше, чем 1. Если происходит E_USER_WARNING мы будем использовать наш пользовательский обработчик ошибок и закончить сценарий:

Пример

<?php
//функция обработчика ошибок
function customError($errno, $errstr) {
  echo «<b>Ошибка:</b> [$errno] $errstr<br>»;
  echo «Закончить Script»;
  die();
}

//установить обработчик ошибок
set_error_handler(«customError»,E_USER_WARNING);

//вызов ошибки
$test=2;
if ($test>=1) {
  trigger_error(«Значение должно быть 1 или ниже»,E_USER_WARNING);
}
?>

Выходные данные приведенного выше кода должны быть примерно такими:

Ошибка: [512] Значение должно быть 1 или ниже
Конец скрипта

Теперь, когда мы научились создавать собственные ошибки и как их вызвать,
давайте посмотрим на ошибки.


PHP Регистрация ошибок

По умолчанию, PHP отправляет отчет об ошибке в систему регистрации на сервер или файл,
в зависимости от того, как конфигурация error_log установлена в php.ini-файл. По
с помощью функции error_log() можно отправлять журнал ошибок в указанный файл или в удаленное место назначения.

Отправка сообщений об ошибках по электронной почте, может быть хорошим способом получения уведомления о конкретных ошибках.

PHP Отправка сообщение об ошибке по электронной почте

В приведенном ниже примере мы отправим электронное письмо с сообщением об ошибке и
сценарий, если возникает ошибка:

Пример

<?php
//функция обработчика ошибок
function customError($errno, $errstr) {
  echo «<b>Ошибка:</b> [$errno] $errstr<br>»;
  echo «Веб-мастер был уведомлен»;
  error_log(«Ошибка: [$errno] $errstr»,1,
  «someone@example.com»,»От: webmaster@example.com»);
}

//установить обработчик ошибок
set_error_handler(«customError»,E_USER_WARNING);

//вызов ошибки
$test=2;
if ($test>=1) {
  trigger_error(«Значение должно быть 1 или ниже»,E_USER_WARNING);
}
?>

Выходные данные приведенного выше кода должны быть примерно такими:

Ошибка: [512] Значение должно быть 1 или ниже
Веб-мастер был уведомлен

И почта, полученная из кода выше, выглядит так:

Ошибка: [512] начение должно быть 1 или ниже

Не должно использоваться со всеми ошибками. Регулярные ошибки должны быть зарегистрированы на
сервере, использующий систему регистрации PHP по умолчанию.


Понравилась статья? Поделить с друзьями:

Не пропустите эти материалы по теме:

  • Яндекс еда ошибка привязки карты
  • Php pdo вывод ошибок
  • Php вызвать 500 ошибку
  • Php pdo mysql ошибка
  • Php вывод ошибок 500

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии