PHP exception error handling

Errors and exceptions

Errors and anomalies are not the same in PHP, they indicate a problem with the code, and can provide an error message.

Points:

  • Error opportunities arise earlier than abnormal
  • Error can be delegated to a global error handler process, some errors can not be recovered, it will cause the script to stop
  • Abnormal first instantiation (Exception class), then throws, it can be captured (try ... catch)
  • Abnormal after capture can be treated in situ, without stopping the script (Any exception uncaught cause the script to stop)

The use of exceptions:

  • Initiative: in the face of irreparable situation (the current context do not know how to deal with) initiative thrown out, handed over to the user process

    eg. the database connection time-out, the incoming parameter type does not meet the conditions.

    eg., and components of the framework are particularly unable to determine how to handle the abnormal condition, usually throws an exception, referred to specific users to deal with.

  • Passive defense: predict potential problems, mitigate the effects (likely to throw an exception code in the try / catch block)

PHP 7 Note :

In PHP 7, most errors are as Error exception is thrown, it can be captured.

If you do not be caught and did not register an exception handler (by set_exception_handler () registration), will be in the traditional manner (refer to previous PHP7 version): is reported as a fatal error (Fatal Error), can be set_error_handler () processing.

Exception class

PHP built-in exceptions categories:

SPL extended exception class (inherit from the Exception class):

Error class (PHP> = 7)

  • Throwable
    • Error
      • ArithmeticError
        • DivisionByZeroError
      • AssertionError
      • ParseError
      • TypeError
    • Exception
      • ...

Note: In PHP 7, Error and Exception are inherited from Throwable, so when captured (try ... catch) can simultaneously capture exceptions and errors by capturing Throwable to

try {
    // do something
} catch (\Throwable $e) {
    // log error or sth.
}

error

php can trigger different types of errors:

  • Fatal Error
  • Runtime Error
  • Compile-time error
  • Startup Errors
  • The user triggers an error (rare)

Error Reporting Level

error_reporting(int $level);

PHP 5.3 and above, the default error reporting level is E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED(will not show E_NOTICE , E_STRICT , E_DEPRECATED )

PHP Manual All error level

Part of the error level explanation:

Error Level Explanation Suggest
E_NOTICE Notification runtime. It indicates that the script encountered may manifest itself as an error, but the script running inside there may be similar notice. Use during development, bug in the code that may arise will be a warning, save debugging time
E_STRICT Enable PHP proposed changes to the code, the code has to ensure the best interoperability and forward compatibility.
E_ALL does not include E_STRICT, so the default is not activated
Use during development
E_DEPRECATED Notification runtime. Will be enabled code may not work in future versions warning. Open

Error Reporting

Error Reporting follow the principle of

  • To report an error
  • Development environment to display an error
  • Production environment to not display error (security reasons)
  • Development and production environments must log errors

Note distinguish report errors and errors show the difference between these two concepts.

php.ini

Development environment is recommended error reporting

;显示错误
display_startup_errors = On
display_errors = On

; Report errors
error_reporting = - 1

; Recording error
log_errors = the On

Production environment is recommended error reporting

;显示错误
display_startup_errors = Off
display_errors = Off

; Error Report
the error_reporting = E_ALL & ~ E_NOTICE

; Recording error
log_errors = the On

Some parameters to explain

parameter Explanation Suggest
display_errors Whether error information is provided as part of the output to the screen or hidden from the user without displaying Development environment opens
a production environment Be sure to turn off
display_startup_errors Even if display_errors is set to ON, PHP error messages during startup will not be displayed. It is strongly recommended except for debugging purposes, the display_startup_errors set to off. Development environment opens
a production environment Be sure to turn off
log_errors Is set to run a script error message is recorded in the server error log or error_log in turn on

Sample code

<?php
// 关闭所有PHP错误报告
error_reporting(0);
// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);
// 报告 E_NOTICE也挺好 (报告未初始化的变量
// 或者捕获变量名的错误拼写)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
// 除了 E_NOTICE,报告其他所有错误
error_reporting(E_ALL ^ E_NOTICE);
// 报告所有 PHP 错误 (参见 changelog)
error_reporting(E_ALL);
// 报告所有 PHP 错误
error_reporting(-1);
// 和 error_reporting(E_ALL); 一样
ini_set('error_reporting', E_ALL);
?>

Global exception handler

Catch all uncaught exception: by set_exception_handlerregistered global exception handler.

function

set_exception_handler ( callable $exception_handler ) : callable
// 注册异常处理程序
set_exception_handler('handleException');
// 重置异常处理程序为默认值
// set_exception_handler(null);
// 还原成之前的异常处理程序
// restore_exception_handler();    
// < PHP 7
handleException(Exception $ex)
{
    // 记录错误日志
    echo "Uncaught exception: " , $ex->getMessage(), "\n";
    // 开发环境显示调试信息(推荐 filp/whoops 扩展包)
    // ...
    // 生产环境显示对用户友好的页面(信息)
    // ...
}
// >= PHP 7
// 大多数错误抛出 Error 异常, 也能被捕获, 因此参数类型必须是 Throwable, 否则会引起问题.
handleException(Throwable $ex)
{
    // ...
}

In the user-defined exception handling internal functions, you can do some processing according to the situation:

  • Error Logging
  • web page rendering errors
  • console rendering error

Global error handler

By setting a global error handler, use their own customized way to intercept and process PHP errors, including but not limited to:

  • Record detailed error log
  • Do clean up the recovery of data / file
  • ErrorException converted into an object, and then the flow of the processing exception to handle errors.

Sign up global error handler

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

$error_typesSpecify the type of error would be intercept the error handler (unless the function returns false), are not error_report()affected.

Handler

# 错误处理函数参数
# $errno 错误等级(对应 E_* 常量)
# $errstr 错误消息
# $errfile 发生错误的文件名
# $errline 发生错误的行号
# $errcontext 一个数组, 指向错误发生时可用的符号表(可选参数), 通常不用(php7.2后废弃)
function error_handler(int $errno, string $errstr, string $errfile, int $errline, array $errcontext) {
    // 处理错误
}

When the statement is prefixed by @ error occurs, $ errno is 0

  • The script continues from the wrong place at the end of the error handling function (and therefore need to take the initiative to call, if necessary, die()or exit()to end the script)

  • If an error occurs before the execution of the script (such as file upload) is not called custom error handler because it is not registered at that time.
  • If the function returns FALSE , standard error processing program will continue to call.

The type of error can not be captured

The following levels of error can not be captured by a user-defined error handler:

Error Level Explanation
E_ERROR Fatal run-time errors, generally unrecoverable (problems eg. Due to memory allocation)
E_PARSE Parsing errors at compile time, generated by the parser
E_CORE_ERROR PHP initial start-fatal error occurs during generated by php engine core
E_CORE_WARNING PHP initial startup warnings (non-fatal errors) that occur during generated by php engine core
E_COMPILE_ERROR Fatal errors at compile time. Similarly E_ERROR , but it is generated by the Zend Scripting Engine.
E_COMPILE_WARNING Warnings (non-fatal errors) at compile time. Similarly E_WARNING , but is generated by the Zend Scripting Engine.

And calling  set_error_handler ()  Most of the file where the generated function  E_STRICT .

These errors can not be captured, can be register_shutdown_function()processed (but the script will still end)

Sample code

function handleError($errno, $errstr, $errfile = '', $errline = 0)
{
    if (!(error_reporting() & $errno)) {
        // 错误类型未包含在 error_reporting() 里, 因此将它交由PHP标准错误处理程序来处理
        return false;
    }
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

The error is converted to an exception

Development / production environments handling errors and exceptions

Development environment

php default error message is very bad, in order to better help the debugger, you can use filp / whoops expansion pack.

installation

composer require filp/whoops

Use (web)

$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();

If php script trigger PHP errors, or application does not catch exceptions, the developer can see a graphical diagnostic page Whoops.

Available processor

Production Environment

Recording error information is typically used error_log()function to record the error message to the file system or syslog.

error_log ( string $message [, int $message_type = 0 [, string $destination [, string $extra_headers ]]] ) : bool

message_type parameter setting errors should be sent to where. Possible types of information are the following:

0 messagePHP is sent to the system log, use the operating system logging mechanism or a file, depending on the error_log directive sets what. This is the default option.
1 messageParameter sent to destinationthe mail address settings. The fourth parameter extra_headerswill only be used in this type there.
2 It is no longer an option.
3 messageIt is sent to the location for destinationthe file. Character messagedoes not default to be treated as a new line.
4 message SAPI sent directly to a log handler.

A better option is to use monolog / monolog extended package

<?php
require "vendor/autoload.php";
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// create a log channel
$log = new Logger('name');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
// add records to the log
$log->warning('Foo');
$log->error('Bar');

Example: Monolog logging in a production environment, a serious error mail notification

依赖: swiftmailer/swiftmailer

require "vendor/autoload.php";
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SwiftMailerHandler;
date_default_timezone_set('Asia/Shanghai');
// 设置monolog
$logger = new Logger('my-app-name');
$logger->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));
// 添加SwiftMailer Handler, 遇到严重错误时使用邮件通知
// Create the Transport
$transport = (new Swift_SmtpTransport('smtp.example.org', 25))
  ->setUsername('your username')
  ->setPassword('your password');
// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transport);
// Create a message
$message = (new Swift_Message('Wonderful Subject'))
  ->setFrom(['[email protected]' => 'John Doe'])
  ->setTo(['[email protected]', '[email protected]' => 'A name']);
$logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL));
// 使用日志记录器
$logger->critical('The server is on fire!');

Php callback function is aborted

register_shutdown_function

register_shutdown_function(function () {
    // do sth...
}, $para1, $param2, ...)

A registration callback, it will execute the script to complete or exit () after the call.

Note:

  • Can register multiple callbacks (not overwrite each other, in order to call in accordance with the registration order), when the php script is invoked to abort.

  • If you call the internal methods registered Exit () , then all the processing is aborted, and the suspension of other registered callbacks will no longer be called.

As part of the error it can not be set_error_handlercaptured, and therefore need to cooperate register_shutdown_function, to determine the cause of the script exits, because if a fatal error is not caught, you will need to deal with (logging, etc.)

register_shutdown_function('handleShutdown');
function handleShutdown()
{
    // 如果是因为严重错误(未被捕获)导致脚本退出, 则需要处理(作为对 set_error_handler的补充)
    if (! is_null($error = error_get_last()) && isFatal($error['type'])) {
        // handleException() 函数同时处理 set_exception_handler
        handleException(new \ErrorException(
            $error['message'], $error['type'], 0, $error['file'], $error['line'],
        ));
    }
}
function isFatal($type)
{
    // 以下错误无法被 set_error_handler 捕获: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING
    return in_array($type, [E_COMPILE_ERROR, E_CORE_ERROR, E_ERROR, E_PARSE]);
}

Note:

Process aborted function will not be called when the signal SIGTERM or SIGKILL kill. Can pcntl_signalthen capture signal in which the call exit()to suspend normal.

Article reprinted from https://www.cnblogs.com/youjiaxing/p/10310658.html

Published 41 original articles · won praise 21 · views 70000 +

Guess you like

Origin blog.csdn.net/u010324331/article/details/89565154