实例讲解PHP异常PHP异常的概念内置异常类异常可以冒泡传递自定义异常类自定义异常处理器像处理异常一样处理错误

PHP异常的概念

PHP中的异常与错误是两个不同的概念,异常是指程序运行与预期不一致,需要由开发人员手动抛出。

error_reporting(-1);
$num = NULL;
try {
    $num = 3/0;
} catch (Exception $e) {
    echo $e->getMessage();
}

程序报Warning: Division by zero错误,而不是异常

要想程序抛出异常,需要由开发人员手动抛出:

error_reporting(-1);
$num = NULL;
try {
    $num1 = 3;
    $num2 = 0;
    if ($num2 == 0) {
        throw new Exception("0不能作为除数"); // 手动抛出异常
    }
} catch (Exception $e) { // 捕获异常
    echo $e->getMessage();
}

PHP

内置异常类

PHP有一些内置的异常类,能够自动捕获异常

header('content-type:text/html;charset=utf-8');
try {
    $pdo = new Pdo("mysql:host=localhost;dbname=mysql", 'root', 'nothing'); // 密码随便填,故意写错
    // 并没有手动抛异常
    var_dump($pdo);
} catch (PDOException $e) {
    echo $e->getMessage() . "<br />";
}

echo "测试内置的异常类";

结果如下:

SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)
测试内置的异常类

异常可以冒泡传递

错误一经出现就要马上处理,而异常是可以冒泡传递的。因此异常可以嵌套。如果所在层的异常抛出后没有被本层捕获,就会寻找上层的捕获程序

多层异常嵌套

header('content-type:text/html;charset=utf-8');
try {
    try {
        throw new Exception('测试异常1');
    } catch (Exception $e) {
        echo $e->getMessage() . "--第二层<br />";
        try {
            throw new Exception('测试异常2');
        } catch (Exception $e) {
            echo $e->getMessage() . "--第三层<br />";
        }
    }
} catch (Exception $e) {
    echo $e->getMessage() . "--第一层<br />";
}

结果:

测试异常1--第二层
测试异常2--第三层

异常冒泡传递

header('content-type:text/html;charset=utf-8');
try {
    try {
        throw new Exception('测试异常1');
    } catch (Exception $e) {
        echo $e->getMessage() . "--第二层<br />";
        throw new Exception('测试异常2'); // 当前层并没有catch捕获此异常,因此会到外层去寻找捕获
    }
} catch (Exception $e) {
    echo $e->getMessage() . "--第一层<br />";
}
测试异常1--第二层
测试异常2--第一层

自定义异常类

自定义的异常类需要继承Exception,可以重写父类的两个方法:__construct__toString

class MyException extends Exception
{
    public function __construct($message = "", $code = 0, Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }

    public function __toString()
    {
        $message = "哈哈,出现异常了,是不是又写了一天的bug啊<br />";
        $message .= $this->message;
        return $message;
    }

    /**
     * 自定义的方法
     */
    public function test()
    {
        echo "异常的测试方法<br />";
    }
}

try {
    throw new MyException('这是自定义的异常');
} catch (MyException $e) {
    echo $e;
    echo $e->getMessage();
    $e->test();
}

结果:

哈哈,出现异常了,是不是又写了一天的bug啊
这是自定义的异常这是自定义的异常异常的测试方法

还可以分类捕获异常:

$type = 1;

try {
    if ($type == 1) {
        throw new Exception('系统异常');
    } else {
        throw new MyException('这是自定义的异常');
    }
} catch (MyException $e) {
    echo $e;
    echo $e->getMessage();
    $e->test();
} catch (Exception $e) {
    echo $e->getMessage();
}

分类捕获异常时,系统异常基类要放到最后,不然会拦截到自定义的异常

自定义异常处理器

使用set_exception_handler函数可指定函数接管异常处理,restore_exception_handler函数能恢复到上一次定义过的异常处理函数

header('content-type:text/html;charset=utf-8');
function exceptionHandler_1($e)
{
    echo $e->getMessage() . "<br />";
    echo "我来接!自定义的异常处理器1--" . __FUNCTION__ . "<br />";
}

function exceptionHandler_2($e)
{
    echo $e->getMessage() . "<br />";
    echo "放着我来!自定义的异常处理器2--" . __FUNCTION__ . "<br />";
}

set_exception_handler('exceptionHandler_1');
set_exception_handler('exceptionHandler_2');

// 恢复到上一次定义过的异常处理函数
restore_exception_handler();
throw new Exception("异常信息,哪个处理器来接?");

// 抛出异常后,程序随即中止
echo "程序不会继续往下跑...<br />";

结果:

异常信息,哪个处理器来接?
我来接!自定义的异常处理器1--exceptionHandler_1

像处理异常一样处理错误

通过set_error_handler函数,我们可以捕获错误,像处理异常一样。

header('content-type:text/html;charset=utf-8');

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

// 不开启错误处理的情况下,默认报 warning 错误。开启后,不会报错,而是输出异常信息
set_error_handler('exception_error_handle');

try {
    echo gettype();
} catch (Exception $e) {
    echo $e->getMessage();
}

结果:

gettype() expects exactly 1 parameter, 0 given

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员互动联盟

【答疑释惑】c/c++有办法加快程序进入main()前的速度吗

一、答案是Yes。 因为在执行main函数之前,程序会进行很多工作,包括调用系统API,初始化环境。 你能触及到的就是全局变量和静态变量,这些初始化工作也都在m...

3185
来自专栏magicsoar

C语言和go语言之间的交互 - C语言中使用go语言,使用的go语言又使用了c语言

一、go语言中使用C语言 go代码中使用C代码,在go语言的函数块中,以注释的方式写入C代码,然后紧跟import “C” 即可在go代码中使用C函数 ? 代码...

34610
来自专栏大闲人柴毛毛

三分钟理解“模板方法模式”——设计模式轻松掌握

模板方法模式的官方定义: 在模板方法模式中,只定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定...

36510
来自专栏mathor

Java自增自减运算符神坑笔试题

1423
来自专栏公众号文章

Golang 入门系列(三)Go语言基础知识汇总

前面已经了 Go 环境的配置和初学Go时,容易遇到的坑,大家可以请查看前面的文章 https://www.cnblogs.com/zhangweizhong/c...

862
来自专栏算法修养

PHP 学习笔记之一:thinkPHP的volist标签

Volist标签主要用于在模板中循环输出数据集或者多维数组。 属性: name : 必须,输出数据模板变量,后台提供的变量。 id : 必须,是循环变量,可...

4769
来自专栏WebDeveloper

跟我学习php字符串常用函数-下篇

1> mixed parse_url ( string $url [, int $component = -1 ] )

922
来自专栏Linyb极客之路

并发编程之Synchronized关键字

一、Synchronized的基本使用 Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchronized的作...

2926
来自专栏海天一树

小朋友学Java(5):静态方法

先编写程序: class Demo { public void fun1() { System.out.println("Hello")...

2866
来自专栏代码世界

Python之内置函数

内置函数 python里的内置函数。截止到python版本3.6.2,现在python一共为我们提供了68个内置函数。它们就是python提供给你直接可以拿来使...

3167

扫码关注云+社区

领取腾讯云代金券