PHP中的异常处理

1.什么是异常?异常和错误有什么区别?

1.异常:程序运行与预期不太一致,与错误是两个不同的概念!
2.抛出和捕获异常
3.多个catch块的时候基类要往后放,否则基类捕获异常后就不会往下继续捕获了!
3.先出现错误,在出现异常,所以写api的时候一定要把display_errors关掉
4.PHP的内置异常

error_reporting(-1);
ini_set('display_errors','off');

//pdo内置异常类
try {
    $pdo = new PDO('mysql:host=localhost;dbname=mysql', 'brave', '123456');
    var_dump($pdo);
    echo '<hr/>';
    echo 'continue.......';
} catch (Exception $e) {
    echo $e->getMessage();
}
echo 'this is a test.......';

echo '<hr/>';

//spl文件读写内置异常类
try {
    $splObj = new SplFileObject('test.txt', 'r');
    echo 'read file';
} catch (RuntimeException $e) {
    echo $e->getMessage();
}
echo 'continue.......';

echo '<hr/>';
 
 
  • 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
  • 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

2.异常的基本语法结构

    try {
        //需要进行异常处理的代码
        throw语句抛出
    } catch (PdoException $e) {

        try {
             throw语句抛出
        } catch (Exception $e) {

        }

    } catch (FileException $e) {

    } catch (CustomException $e) {

    }

    //other code
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

3.如何自定义异常类?

error_reporting(-1);
ini_set('display_errors','off');
class MyException extends Exception{

    function __construct($message, $code=0)
    {
        parent::__construct($message, $code);
    }

    public function __toString(){
        $message = "<h2>出现异常了,信息如下</h2>";
        $message .="<p>".__CLASS__." [{$this->code}]:{$this->message}</p>";
        return $message;
    }

    public function test(){
        echo 'this is a test';
    }

    public function stop(){
        exit('script end..............<hr/>');
    }

    //自定义其他方法
}

try {
    echo '出现异常了!';
    throw new MyException("测试自定义异常!", 11);
} catch (MyException $e) {
    echo $e->getMessage(); 
    echo '<hr/>';
    echo $e;
    echo '<hr/>';
    $e->stop();
    $e->test();
}
 
 
  • 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
  • 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

4.自定义文件异常类

error_reporting(-1);
ini_set('display_errors','off');

class FileException extends Exception
{
    public function getDetails()
    {
        switch ($this->code) {
            case 0:
                return '没有提供文件!';
                break;

            case 1:
                return '文件不存在!'." trace".$this->getTraceAsString().$this->getLine();
                break;

            case 2:
                return '不是一个文件!'." trace".$this->getTraceAsString().$this->getLine();
                break;

            case 3:
                return '文件不可写!';
                break;

            case 4:
                return '非法文件的操作模式!';
                break;

            case 5:
                return '数据写入失败!';
                break;

            case 6:
                return '文件不能被关闭!';
                break;

            default:
                return '非法!';
                break;
        }
    }
}

class WriteData{
    private $_message='';
    private $_fp=null;

    public function __construct($filename=null, $mode='w'){
        $this->_message="文件:{$filename} 模式:{$mode}";
        if (empty($filename)) {
            throw new FileException($this->_message, 0);
        }
        if (!file_exists($filename)) {
            throw new FileException($this->_message, 1);
        }
        if (!is_file($filename)) {
            throw new FileException($this->_message, 2);
        }
        if (!is_writable($filename)) {
            throw new FileException($this->_message, 3);
        }
        if (!in_array($mode, array('w', 'w+', 'a', 'a+'))) {
            throw new FileException($this->_message, 4);
        }
        $this->_fp=fopen($filename, $mode);
    }

    /**
     * [write 写数据]
     * @param  [type] $data [description]
     * @return [type]       [description]
     */
    public function write($data){
        if (@!fwrite($this->_fp, $data.PHP_EOL)) {
            throw new FileException($this->_message, 5);
        }
    }

    /**
     * [close 关闭文件句柄]
     * @return [type] [description]
     */
    public function close(){
        if ($this->_fp) {
            if (@!fclose($this->_fp)) {
                throw new FileException($this->_message, 6);
                $this->_fp=null;
            }
        }
    }

    public function __destruct(){
        $this->close();
    }
}

try {
    $fp = new WriteData('test.txt', 'w');
    $fp->write('this is a test');
    $fp->close();
    echo '数据写入成功!';
} catch (FileException $e) {
    echo '出问题了:'.$e->getMessage().' 详细信息如下:'.$e->getDetails();
}
 
 
  • 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
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 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
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104

5.使用观察者模式处理异常

  1. 定义观察(异常)的类, 可以在代码中动态的添加观察者
    /**
     * 观察(异常)的类, 可以在代码中动态的添加观察者
     */
    class Observable_Exception extends Exception
    {
        public static $_observers=array();
        public static function attach(Exception_Observer $observer){
            self::$_observers[]=$observer;
        }

        public function __construct($message=null, $code=0){
            parent::__construct($message, $code);
            $this->notify();
        }

        public function notify(){
            foreach (self::$_observers as $observer) {
                $observer->update($this);
            }
        }

    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

2.定义异常观察者基类用于规范每一个观察者

    /**
     * 观察者基类,用于规范每一个观察者
     */
    interface Exception_Observer{
        //强制指定必须是我们规定的观察类
        public function update(Observable_Exception $e);

    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.定义日志观察者

    /**
     * 定义日志观察者
     */
    class Logging_Exception_Observer implements Exception_Observer{
        public $_filename='./log_exception.log';

        public function __construct($filename=null){
            if ($filename!==null && is_string($filename)) {
                $this->_filename=$filename;
            }
        }

        public function update(Observable_Exception $e){
            $message="时间:".date('Y-m-d H:i:s').PHP_EOL;
            $message.="信息:".$e->getMessage().PHP_EOL;
            $message.="追踪信息:".$e->getTraceAsString().PHP_EOL;
            $message.="文件:".$e->getFile().PHP_EOL;
            $message.='行号:'.$e->getLine().PHP_EOL;
            error_log($message, 3, $this->_filename);
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

4.定义邮件观察者

    /**
     * 定义邮件观察者
     */
    class Email_Exception_Observer implements Exception_Observer{
        public $_email='732578448@qq.com';

        public function __construct($email=null){
            if ($email!==null && filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $this->_email=$email;
            }
        }

        public function update(Observable_Exception $e){
            $message="时间:".date('Y-m-d H:i:s').PHP_EOL;
            $message.="信息:".$e->getMessage().PHP_EOL;
            $message.="追踪信息:".$e->getTraceAsString().PHP_EOL;
            $message.="文件:".$e->getFile().PHP_EOL;
            $message.='行号:'.$e->getLine().PHP_EOL;
            error_log($message, 1, $this->_email);
        }
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

5.执行测试

error_reporting(-1);
ini_set('display_errors','off');
//引入观察异常的类
require 'Observable_Exception.php';
//引入观察者基类
require 'Exception_Observer.php';
//引入日志观察者
require 'Logging_Exception_Observer.php';
//引入邮件观察者
require 'Email_Exception_Observer.php';

Observable_Exception::attach(new Logging_Exception_Observer());
//自定义地址记录错误异常
Observable_Exception::attach(new Logging_Exception_Observer('/tmp/test11.log'));
Observable_Exception::attach(new Email_Exception_Observer());
//自定义邮件接收人记录错误异常
Observable_Exception::attach(new Email_Exception_Observer('123456@qq.com'));
class MyException extends Observable_Exception{
    public function test(){
        echo 'this is a test!';
    }

    public function test1(){
        echo '我是 自定义的方法处理这个异常!';
    }
}

try {
    throw new MyException("出现异常了,记录一下下!");

} catch (MyException $e) {
    echo $e->getMessage();
    echo '<hr/>';
    $e->test();
    echo '<hr/>';
    $e->test1();
}
 
 
  • 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
  • 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

6.自定义异常处理器(set_exception_handler)?

1.目的1处理所有未捕获的异常
2.目的2处理所有我们为放到try catch中的异常

3.自定义异常处理函数
ini_set('display_errors','off');
function exceptionHandler_1($e){
  echo '自定义异常处理器1'.__FUNCTION__;
  echo '异常信息:'.$e->getMessage();
}

function exceptionHandler_2($e){
  echo '自定义异常处理器2'.__FUNCTION__;
  echo '异常信息:'.$e->getMessage();
}
set_exception_handler('exceptionHandler_1');
set_exception_handler('exceptionHandler_2');
//恢复到上一次定义过的异常处理函数
restore_exception_handler();
throw new Exception('测试');
echo 'continue........';
echo '<hr/>';
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
4.自定义异常处理类
/**
 * 自定义错误异常类
 */
class ExceptionHandler{
    protected $_exception;
    protected $_logFile='./testExceptionHandler.log';

    function __construct(Exception $e){
        //保存异常对象
        $this->_exception = $e;
    }

    public static function handle(Exception $e){
        $self = new self($e);
        $self->log();
        echo $self;
    }

    public function log(){
        $msg=<<<EOF
        出现了通知错误,如下
产生通知的文件:{$this->_exception->getFile()}<br>
产生通知的信息:{$this->_exception->getTraceAsString()}
产生通知的行号:{$this->_exception->getLine()}
产生通知的错误号:{$this->_exception->getCode()}
产生通知的时间:{$datetime}
\n
EOF;
        echo $msg;
        error_log($msg, 3, $this->_logFile);
    }

    public function __toString(){
        $message = <<<EOF
        <!DOCTYPE html>
        <html>
        <head>
            <title></title>
        </head>
        <body>
            <h1>出现异常了。。。。。</h1>
            <p>刷新下试试</p>
        </body>
        </html>
EOF;
        return $message;
    }
}



ini_set('display_errors','off');
set_exception_handler(array('ExceptionHandler', 'handle'));

//放在try catch中的throw
try {
    throw new Exception("this is a test!",20010);
} catch (Exception $e) {
    echo $e->getMessage();
}

//没放在try catch中的throw
throw new Exception("测试未捕获的自定义的异常处理器hello world!",2008);
 
 
  • 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
  • 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

7.如何像处理异常一样处理PHP的错误?

1.通过ErrorException

function exception_error_handler($errno, $errstr, $errfile, $errline){
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler('exception_error_handler');
try {
    echo gettype();
} catch (Exception $e) {
    echo $e->getMessage();
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2.自定义异常类

class ErrorToException extends Exception{

    public static function handle($errno, $errstr)
    {
        throw new self($errstr, $errno);
    }
}

ini_set('display_errors', 'off');
set_error_handler(array('ErrorToException', 'handle'));
set_error_handler(array('ErrorToException', 'handle'),E_USER_WARNING|E_WARNING);

try {
    echo $test;
    gettype();
    trigger_error('test',E_USER_WARNING);
} catch (Exception $e) {
    echo $e->getMessage();
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

8.在发生错误的时候将用户重定向到另一个页面

class ExceptionRedirectHandler{
    protected $_exception;
    protected $_logFile='./redirectLog.log';
    protected $_redirect='404.html';

    public function __construct(Exception $e){
        $this->_exception=$e;
    }

    public static function handle(Exception $e){
        $self = new self($e);
        $self->log();
        while (@ob_end_clean());
        header('HTTP/1.1 307 Temporary Redirect');
        header('Cache-Control:no-cache,must-revalidate');
        header('Expires: Wed, 01 Jul 2015 07:40:45 GMT');
        header('Location:'.$self->_redirect);
        exit(1);
    }

    public function log($value=''){
        error_log($this->_exception->getMessage().PHP_EOL, 3, $this->_logFile);
    }
}

ini_set('display_errors','off');
set_exception_handler(array('ExceptionRedirectHandler', 'handle'));
$link = mysql_connect('localhost', 'brave', '123456123');
if (!$link) {
    throw new Exception("数据库受到攻击了,赶快去看看吧!");

}
 
 
  • 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
  • 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

9.设置自定义错误和异常需要传递的参数

异常传递:$msg, $code
错误传递:$errno, $errmsg, $errfile, $errline 可看MyErrorHandler.php

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值