zoukankan      html  css  js  c++  java
  • PHP的错误和异常处理

    错误处理


    错误报告级别

            如果希望在php脚本中,将某个级别的错误消息报告给他,则必须在配置文件php.ini中,将display_errors指令的值设置为On,开启输出错误报告的功能。也可以在php脚本中调用ini_set()函数,动态配置文件php.ini中的某个指令。

            如果display_error被启动,就会显示满足已设置的错误级别的所有错误报告。当用户在访问网站时,看到现实的这些消息不仅会感到迷惑,而且还可能会更过多地泄露有关服务器的信息,是服务器变得不安全。
    调整错误报告级别
            调整错误报告的级别实现,可以通过以下两种方法设置错误报告级别:
    • 可以通过在配置文件php.ini中,修改配置指令error_reporting的值,修改成功后重新启动Web服务器,则每个PHP脚本都可以按调整后的错误报告。下面是修改php.ini配置文件的示例。列出几种为error_reporting指令设置不同级别的值的方式,可以把位运算符[&(与)、|(或)、~(非)]和错误级别常量一起使用。
    1
    2
    3
    4
    5
    6
    ;可以抛出任何非注意的错误,默认值
    error_reporting = E_ALL &~ E_NOTICE
    ;只考虑致命的运行时错误、解析错误和核心错误
    error_reporting = E_ERROE | E_PARSE | E_CORE_ERROR
    ;报告除用户导致的错误之外的所有错误
    error_reporting = E_ALL &~(E_USER_ERROR | E_USER_WARNING |E_USER_NOTICE)
    • 或者在php脚本中使用error_reporting()函数,基于各个脚本来调整这种行为。这个函数用于确定php应该在特定的页面内报告哪些类型的错误。该函数获取一个数字或错误级别常量作为参数。
    1
    2
    3
    error_reporting(0);                //设置为0会完全关闭错误报告
    error_reporting(E_ALL);            //将会向PHP报告发生的每个错误
    error_reporting(E_ALL & ~ E_NOTICE); //可以抛出任何非注意的错误报告
    其他配置指令
    使用trigger_error()函数来替代die()
            die()等同于exit(),两者如果执行都会终止PHP程序,而且可以在退出程序之前输出一些错误报告。trigger_error()则可以生成一个用户警告来代替,是程序更具有灵活性。
    自定义错误处理
            通常使用set_error_handler()函数去设置用户自定义的错误处理函数,该函数用于创建运行时期间的用户自己的错误处理方法,返回就的错误处理程序,若失败,则返回null。该函数有两个参数,其中第一个参数是必选的,需要一个回调函数,规定发生错误时运行的函数。这个回调函数一定要声明4个参数,否则无效,按顺序分别是是否存在错误、错误信息、错误文件和错误行号。set_error_handler()函数的第二个参数是可选的,规定在哪个错误报告级别会显示用户定义的错误。默认是"E_ALL"。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    <?php
        error_reporting(0);                 //屏蔽程序中的错误
         
        /**
            定义Error_Handler函数,作为set_error_handler()函数的第一个参数"回调"
            @param  int     $error_level        错误级别
            @param  string  $error_message  错误信息
            @param  string  $file           错误所在文件
            @param  int     $lin                错误所在行数
        */
        function error_handler($error_level, $error_message, $file, $line) {
            $EXIT = FALSE;
            switch( $error_level ) {
                //提醒级别
                case E_NOTICE:
                case E_USER_NOTICE;
                    $error_type = 'Notice';
                    break;
                     
                //警告级别
                case E_WARNING:
                case E_USER_WARNING:
                    $error_type = 'Warning';
                    break;
                 
                //错误级别
                case E_ERROR:
                case E_USER_ERROR:
                    $error_type = 'Fatal Error';
                    $EXIT = TRUE;
                    break;
                     
                //其他末知错误
                default:
                    $error_type = 'Unknown';
                    $EXIT = TRUE;
                    break;
            }
             
            //直接打印错误信息, 也可以写文件,写数据库,反正错误信息都在这,任你发落
            printf ("<font color='#FF0000'><b>%s</b></font>: %s in <b>%s</b> on line <b>%d</b><br> ", $error_type, $error_message, $file, $line);
             
            //如果错误影响到程序的正常执行,跳转到友好的错误提示页面
            if(TRUE == $EXIT) {
                echo '<script>location = "err.html"; </script>';
            }
        }
         
        //这个才是关键点, 把错误的处理交给error_handler()
        set_error_handler('error_handler');
         
        //使用末定义的变量要报 notice 的
        echo $novar;
         
        //除以0要报警告的
        echo 3/0;
         
        //自定义一个错误
        trigger_error('Trigger a fatal error', E_USER_ERROR);
    • 系统直接报Fital Error这个方法是捕获不到的,遇到这种错误是必须解决的,所以系统会直接终止程序运行。
    • E_ERROR、E_PARSE、E_CORE_ERROR、ERROR_WARNING/E_COMPILE_ERROR、ERROR_COMPILE_WARNING是不会被这个句柄处理的,也就是会用原始的方式显示出来。不过出现这些错误都是编译或PHP内核错误,在通常情况下不会发生。
    • 使用set_error_handler()后,error_reporting()将会失效。也就是所有的错误都会交给自定义的函数处理。
    写错误日志
     1、使用指定的文件记录错误报告日志

           如果使用自己指定的文件记录错误日志,一定要确保将这个文件存放在文档目录之外,以减少遭到攻击的可能。并且该文件一定要让PHP脚本的执行用户具有写权限。假设在linux操作系统中,将/usr/local/目录下的config文件作为错误日志文件,并设置Web服务器进程用户具有写的权限。然后在php的配置文件中,将error_log指令的值设置为这个错误日志文件的绝对路径。需要对php.ini中的配置指令做如下修改:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ;将会向php报告发生的每个错误
    error_reporting = E_ALL
    ;不显示满足上条指令所定义规则的所有错误报告
    display_errors = Off
    ;决定日志语句记录的位置
    log_errors = On
    ;设置每个日志想的最大长度
    log_errors_max_len = 1024
    ;指定产生的错误报告写入的日志文件位置
    error_log = /usr/local/error.log

            还可以使用php中的error_log()函数,送出一个用户自定义的错误信息。

    1
    bool error_log(stringmessage[,int message_type[,string destination[,string extra_headers]]])

            第一个参数:必选项,即为要送出的错误信息。

            第二个参数:为整数值,0表示送到操作系统的日志中;1则使用PHP的Mail()函数,发送信息到某Email地址处,第四个参数也会用到;2则将错误信息送到TCP服务器中,此时第三个参数destination表示目的地ip及Port;3则将信息存到文件destination中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?php  
        if(!Ora_Logon($username, $password)){  
            //将错误消息写入到操作系统日志中
            error_log("Oracle数据库不可用!", 0);         
        }
         
        if(!($foo=allocate_new_foo()){
            //发送到管理员邮箱中
            error_log("出现大麻烦了!", 1, "webmaster@www.mydomain.com");  
        }
         
        //发送到本机对应5000端口的服务器中
        error_log("搞砸了!",   2,   "localhost:5000");    
        //发送到指定的文件中
        error_log("搞砸了!",   3,   "/usr/local/errors.log"); 

    2、错误信息记录到操作系统的日志里

            

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ;将会向php报告发生的每个错误
    error_reporting = E_ALL
    ;不显示满足上条指令所定义规则的所有错误报告
    display_errors = Off
    ;决定日志语句记录的位置
    log_erros = On
    ;设置每个日志项的最大长度
    log_errors_max_len = 1024
    ;指定产生的错误报告写入操作系统的日志里
    error_log = syslog

    php还允许想系统syslog中发送定制的消息,php为这个特性提供了需要一起使用的4个专用函数。

    • define_syslog_variables()

            使用openlog()、syslog()及closelog()三个函数之前必须先调用该函数,因为在调用该函数时,他会根据现在的系统环境为下面三个函数初使用化一些必需的常量。

    • openlog()

            打开一个和当前系统中日志器的连接,为向系统插入日志消息做好准备。并将提供的第一个字符串参数插入到每个日志消息中,该函数还需要指定两个将在日志上下文使用的参数。

    • syslog()

           该函数向系统日志中发送一个定制消息。需要两个必选参数,第个参数通过指定一个常量定制消息的优先级。第二个参数则是像系统日志中发送定制的消息,需要提供一个消息字符串,也可以是php引擎在运行时提供的错误字符串。

    • closelog()
            该函数在向系统日志中发送完成定制消息以后调用,关闭由openlog()函数打开的日志连接。

    1
    2
    3
    4
    5
    6
    7
    <?php
        define_syslog_variables();
         
        openlog("PHP5", LOG_PID , LOG_USER);
        syslog(LOG_WARNING, "警告报告向syslog中发送的演示,警告时间:".date("Y/m/d H:i:s"));
         
        closelog();

    异常处理

    异常处理实现

            在php中,异常必须手动抛出。throw关键字将触发异常处理机制,他是一个语言结构,而不是一个函数,但必须给它传递一个对象作为值。如果在try语句中游艺场对象被抛出,改代码块不会再继续向下执行,而直接转到catch中执行。并传给catch代码块一个对象,也可以理解为被catch代码块不活的对象,其实就是导致异常常被throw语句抛出的对象。

    扩展php那只的异常处理类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <?php
    /* 自定义的一个异常处理类 ,但必须是扩展内异常处理类的子类  */
    class MyException extends Exception{
        //重定义构造器是第一个参数message变为必须被指定的属性
        public function __construct($message, $code=0){
            //可以在这里定义一些自己的代码
            //建议同时调用parent::construct()来检查所有的变量是否已被赋值
            parent::__construct($message,$code);
        }
         
        //重写父类方法,自定义字符串输出的样式
        public function __toString(){
            return __CLASS__.":[".$this->code."]".$this->message."<br/>";
        }
         
        //为这个异常自定义一个处理方法
        public function customFunction(){
            echo "按自定义的方法处理出现的这个类型的异常<br/>";
        }
         
    }
     
    try {
        $error = "允许抛出这个错误";
        throw new MyException($error);
        echo 'Never executed';
    } catch (MyException $e) {
        echo '捕获异常:'.$e;
        $e->customFunction();
    }
    echo "你好!";

    捕获多个异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    <?php
        /* 自定义的一个异常处理类,但必须是扩展内异常处理类的子类 */
        class MyException extends Exception{
            //重定义构造器使第一个参数 message 变为必须被指定的属性
            public function __construct($message, $code=0){
                //可以在这里定义一些自己的代码
                //建议同时调用 parent::construct()来检查所有的变量是否已被赋值
                parent::__construct($message, $code);
            }
            //重写父类中继承过来的方法,自定义字符串输出的样式
            public function __toString() {
                return __CLASS__.":[".$this->code."]:".$this->message."<br>";
            }
     
            //为这个异常自定义一个处理方法
            public function customFunction() {
                echo "按自定义的方法处理出现的这个类型的异常";
            }
        }
         
        /* 创建一个用于测试自定义扩展的异常类MyException */
        class TestException {
            public $var;                                        //用来判断对象是否创建成功的成员属性
     
            function __construct($value=0) {                    //通过构造方法的传值决定抛出的异常
                switch($value){                                 //对传入的值进行选择性的判断
                    case 1:                                     //传入参数1,则抛出自定义的异常对象
                        throw new MyException("传入的值“1” 是一个无效的参数", 5); break;
                    case 2:                                     //传入参数2,则抛出PHP内置的异常对象
                        throw new Exception("传入的值“2”不允许作为一个参数", 6); break;
                    default:                                    //传入参数合法,则不抛出异常
                        $this->var=$value;   break;              //为对象中的成员属性赋值
                         
                }
            }
        }
         
        /* 示例1,在没有异常时,程序正常执行,try中的代码全部执行并不会执行任何catch区块 */
        try{
            $testObj = new TestException();                     //使用默认参数创建异常的测试类对象
            echo "***********<br>";                               //没有抛出异常这条语句就会正常执行
        }catch(MyException $e){                                 //捕获用户自定义的异常区块
            echo "捕获自定义的异常:$e <br>";                  //按自定义的方式输出异常消息
            $e->customFunction();                                //可以调用自定义的异常处理方法
        }catch(Exception $e) {                                  //捕获PHP内置的异常处理类的对象
            echo "捕获默认的异常:".$e->getMessage()."<br>";    //输出异常消息
        }  
        var_dump($testObj);          //判断对象是否创建成功,如果没有任何异常,则创建成功
     
        /* 示例2,抛出自定义的异常,并通过自定义的异常处理类捕获这个异常并处理 */
        try{   
            $testObj1 = new TestException(1);                    //传1时,抛出自定义异常
            echo "***********<br>";                                //这个语句不会被执行
        }catch(MyException $e){                                  //这个catch区块中的代码将被执行
            echo "捕获自定义的异常:$e <br>";
            $e->customFunction();
        }catch(Exception $e) {                                  //这个catch区块不会执行
            echo "捕获默认的异常:".$e->getMessage()."<br>";
        }  
        var_dump($testObj1);                                    //有异常产生,这个对象没有创建成功
     
        /* 示例2,抛出内置的异常,并通过自定义的异常处理类捕获这个异常并处理 */
        try{
            $testObj2 = new TestException(2);                   //传入2时,抛出内置异常
            echo "***********<br>";                           //这个语句不会被执行
        }catch(MyException $e){                                 //这个catch区块不会执行
            echo "捕获自定义的异常:$e <br>";
            $e->customFunction();
        }catch(Exception $e) {                                  //这个catch区块中的代码将被执行
            echo "捕获默认的异常:".$e->getMessage()."<br>";
        }  
        var_dump($testObj2);                                    //有异常产生,这个对象没有创建成功


    错误查询

    error_get_last():

            函数获取最后发生的错误。 

            该函数以数组的形式返回最后发生的错误。 

            返回的数组包含 4 个键和值: 

    • type:错误类型。
    • message:错误消息。
    • file:发生错误所在的文件。
    • line:发生错误所在的行。

            


            







  • 相关阅读:
    四则运算
    读书计划
    典型用户和场景分析
    课堂练习--电梯调度
    重力解锁--用户需求调研
    书籍促销活动优惠问题
    小组开发项目--NABC分析
    梦断代码读后感之终结篇
    结对开发-求环状二维数组最大子数组
    结对开发之大数溢出
  • 原文地址:https://www.cnblogs.com/staven/p/5be088084fdf38af00a380dd41137c0b.html
Copyright © 2011-2022 走看看