PHP之异常处理的概念

Posted 1994july

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP之异常处理的概念相关的知识,希望对你有一定的参考价值。

1.前言

异常表示程序运行与自我预期不一致,与错误是两种概念,且异常必须被手动抛出。

代码分享:https://github.com/mtdgclub/tryCatch

1.1异常和错误区别

错误没办法在调用的时候向上传递,必须马上处理;异常则可以。

错误在触发的时候,必须对脚本做一个错误处理;异常可以自定义处理错误信息。

2.异常的基本语法结构

2.1基本语法代码块

try{
//代码段
}catch(Exception $e){
//捕捉异常并处理
}

举例:

<?php
try{
    $num2=0;
    if($num2==0){
        throw new Exception("这是一个错误,0不能当除数");
    }
}catch(Exception $e){
    echo $e->getMessage();
}

技术图片

注意:PDO是有内置异常类的,比如PDO连接

try{
    $pdo=new PDO("mysql:host=localhost;dbname=mysql",‘root‘,‘‘);
    var_dump($pdo);
    echo ‘continue....‘;
}catch(PDOException $e){
    echo $e->getMessage();
}

技术图片

抛出异常,程序就不向下执行了

2.2自定义异常类

举例:

<?php
class MyException extends Exception{
    public function __construct($message, $code=0)
    {
        parent::__construct($message, $code);
    }
    public function __toString()
    {
        parent::__toString(); // TODO: Change the autogenerated stub
        $message="出现异常了,信息如下:<br />";
        $message.="<p>".__CLASS__."[{$this->code}]:{$this->message}</p>";
        return $message;
    }
}

测试:

<?php
require_once ‘MyException.php‘;
//输出自定义格式
try{
    echo ‘出现异常啊‘;
    throw new MyException(‘测试自定义异常‘,3);
}catch(MyException $e){
    echo $e->getMessage(),‘<hr/>‘;
    echo $e;
}

技术图片

2.3 PHP多个catch进行异常捕获 

<?php
require_once ‘MyException.php‘;
try{
    throw new MyException(‘测试自定义异常‘);
}catch(MyException $e){
    echo $e->getMessage();
}catch(Exception $e){
    echo $e->getMessage();
}
echo ‘continue.....‘;

注意:测试捕获多个异常,建议把基类放在最后捕获

2.4案例:自定义文件写入异常处理类

<?php
/**
 * 案例:自定义文件写入异常处理类
 */
class FileException extends Exception
{
    public function getDetails()
    {
        switch ($this->code) {
            case 0:
                return ‘没有提供文件‘;
                break;
            case 1;
                return ‘文件不存在‘;
                break;
            case 2:
                return ‘不是一个文件‘;
                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 = "<br/>文件:{$filename} <br/>模式:{$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);
    }

    public function write($data)
    {
        if (!fwrite($this->_fp, $data . PHP_EOL)) {
            throw new FileException($this->_message, 5);
        }
    }

    public function close()
    {
        if (!fclose($this->_fp)) {
            throw new FileException($this->_message, 6);
            $this->_fp = null;
        }
    }
}

测试及结果:

<?php
require_once ‘FileException.php‘;
try{
    $fp=new WriteData(‘test.txt‘,‘w‘);
    $fp->write(‘this is a test‘);
    $fp->close();
    echo "数据写入成功~";
}catch(FileException $e){
    echo "出问题了".$e->getMessage()."<br/>详细信息如下:".$e->getDetails();
}

技术图片

2.5记录与发送异常信息

<?php
class LogExeception extends Exception
{
    public function __construct($message, $code=0)
    {
        parent::__construct($message, $code);
        error_log($this->getMessage(),3,‘testLogException.log‘);
    }
}

//测试
try{
    $link=mysqli_connect(‘localhost‘,‘root‘,‘root123‘,‘mysql‘);
    if(!$link) {
        throw new LogExeception(‘数据库连接失败‘);
    }
}catch(LogExeception $e){
    echo $e->getMessage();
}

测试及结果:

技术图片

3.自定义异常处理器

使用set_exeption_handler()函数,该函数是设置一个用户定义的异常处理函数.

3.1第一次测试:不声明自定义异常处理器

<?php
function exeption_handler_1($e)
{
    echo ‘自定义的异常处理器1‘;
    echo ‘异常信息:‘ . $e->getMessage();
}

function exeption_handler_2($e)
{
    echo ‘自定义的异常处理器2‘;
    echo ‘异常信息:‘ . $e->getMessage();
}

throw  new Exception(‘测试‘);

技术图片

如何处理没有被捕获的异常信息,在异常报错前声明自定义异常处理器。

3.2第二次测试:声明自定义异常处理器

<?php
function exeption_handler_1($e){
    echo ‘自定义的异常处理器1‘;
    echo ‘异常信息:‘.$e->getMessage();
}
function exeption_handler_2($e){
    echo ‘自定义的异常处理器2‘;
    echo ‘异常信息:‘.$e->getMessage();
}
//声明自定义异常处理器
set_exception_handler(‘exeption_handler_1‘);
throw  new Exception(‘测试‘);

技术图片

//自定义异常处理器后面声明会覆盖前面声明
set_exception_handler(‘exeption_handler_1‘);
set_exception_handler(‘exeption_handler_2‘);
throw  new Exception(‘测试‘);

技术图片

//声明自定义异常处理器
set_exception_handler(‘exeption_handler_1‘);
set_exception_handler(‘exeption_handler_2‘);
//恢复到上一次定义过的异常处理函数
restore_exception_handler();
throw  new Exception(‘测试‘);

技术图片

注意:使用自定义异常处理器,调用了,程序就不再向下执行

3.3第三次测试:封装自定义异常处理器类

<?php
/**
 * 定义一个类,捕获未捕获的异常信息
 */
class ExceptionHandler
{
    protected $_exception;
    protected $_logFile = ‘ExceptionHandler.log‘;

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

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

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

    public function __toString()
    {
        $message = <<<EOF
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>出现异常了,信息如下</h1>
    <p>刷新一下试试</p>
    <p><a href="mailto:747245429@qq.com">联系管理员看看747245429@qq.com</a></p>
</body>
</html>
EOF;
        return $message;
    }
}

//测试
set_exception_handler(array(‘ExceptionHandler‘,‘handle‘));
throw new Exception(‘测试自定义异常处理器hello world‘);

技术图片

技术图片

放到try{}catch(){}中也可以调用到

技术图片

4.像处理异常一样处理PHP错误

4.1使用PHP定义的错误异常类ErrorException

<?php
//使用set_error_handler()函数将错误信息托管至ErrorException
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler("exception_error_handler");
/* Trigger exception */
try{
    echo gettype();
}catch(Exception $e){
    echo $e->getMessage();
}

技术图片

4.2自定义错误异常类

<?php
/**
 * 自定义一个错误异常类
 * Class ErrorToException
 */
class ErrorToException extends Exception
{
    public static function handle($errno,$errstr){
        throw new self($errstr,$errno);
    }
}
set_error_handler(array(‘ErrorToException‘,‘handle‘));
try{
    echo $test;
}catch(Exception $e){
    echo $e->getMessage();
}

技术图片

我们也可以设定处理级别,如下:

set_error_handler(array(‘ErrorToException‘,‘handle‘));
//只有警告级别才交给其处理
set_error_handler(array(‘ErrorToException‘,‘handle‘),E_USER_WARNING|E_WARNING);

4.3发生错误如何重定向到404页面

<?php
/**
 * 发生错误如何重定向到404页面
 */
class ExceptionRedirectHandler{
    protected $_exception;
    protected $logFile=‘redirectLog.log‘;
    public $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());
        //PHP 实现307重定向的方式
        header(‘HTTP/1.1 307 Temporary Redirect‘);
        //发送一个报头,告诉浏览器当前页面不进行缓存,每次访问必读取最新数据
        header(‘Cache-Control:no-cache,must-revalidate‘);
        //内容过期时间
        header(‘Expires:Sat,28 Mar 2015 13:28:48 GMT‘);
        //强制重定向相对路径
        header(‘Location:‘.$self->redirect);
        exit(1);
    }
    public function log(){
        error_log($this->_exception->getMessage().PHP_EOL,3,$this->logFile);
    }
}
set_exception_handler(array(‘ExceptionRedirectHandler‘,‘handle‘));

$link=mysqli_connect(‘localhost‘,‘root‘,‘root123‘,‘mysql‘);
if(!$link){
    throw new Exception(‘数据库连接失败‘);
}

技术图片

技术图片

5.总结

通过本章回顾,再次认识到了异常和错误的区别、并了解了异常的基本语法、懂得如何制定一个异常类、并完成了自定义文件写入异常处理类案例、用error_log记录与发送异常信息和自定义异常处理器set_exeption_handler()函数使用及封装,希望通过本次学习,能够更好地掌握异常处理相关的函数和方法。

来源:站长

以上是关于PHP之异常处理的概念的主要内容,如果未能解决你的问题,请参考以下文章

Java编程思想之十二 通过异常处理错误

异常处理

异常和TCP通讯

php 异常

Thinkphp5.0之异常处理

Java面向对象之异常(异常处理方式)