0

0

PHP程序员遇到的错误与异常下篇之异常

不言

不言

发布时间:2018-04-14 15:02:11

|

1636人浏览过

|

来源于php中文网

原创

本篇文章介绍的内容是php程序员遇到的错误与异常中的异常问题,现在分享给大家,有需要的朋友可以参考一下

上一篇:那些年,PHPer遇到的错误与异常:上篇之错误

一、PHP中的异常简介及使用

1.1 异常执行流程

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

     未被捕获的异常会报致命错误:Fatal error:Uncaught exception.....

1.2 PHP异常特点

  1. PHP不会主动捕获异常,需要程序中主动抛出 (throw)异常,才能捕获。

  2. throw会自动向上抛出

  3. throw之后的语句不会执行

    立即学习PHP免费学习笔记(深入)”;

  4. try后必须有catch,否则解析错误Parse error

try{
    $num1=3;
    $num2=0;
    if($num2==0){
        throw new Exception('0不能当作除数');
        echo 'this is a test';//看不到
    }else{
        $res=$num1/$num2;
    }
}catch(Exception $e){
    echo $e->getMessage();
}

1.3 PHP内置异常

Php不像java提供了很多异常类,所以很多异常都会当成错误。要想变错误为抛出异常,需要手动throw异常对象

PHP内置异常如:PDOExceptionSplFileObject 可以自动抛出异常,后面的代码可以继续执行。

PHP程序员遇到的错误与异常下篇之异常

PHP程序员遇到的错误与异常下篇之异常

1.4 错误和异常的区别

1.4.1 异常处理

     当异常被抛出,throw后的代码不会继续执行PHP 会尝试查找匹配的 catch 代码块。如果异常没有被捕获,而且又没用使用set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 “Uncaught Exception” (未捕获异常)的错误消息。

1.4.2 异常的基本语法结构

     try - 需要进行异常处理的代码应该放入try代码块内,以便捕获潜在的异常。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常
     throw - 这里规定如何触发异常。每一个trythrow 必须对应至少一个 catch。使用多个catch代码块可以捕获不同种类的异常。
     catch - catch代码块会捕获异常,并创建一个包含异常信息的对象

1.4.3 重新抛出异常

     有时,当异常被抛出时,也许希望以不同于标准的方式对它进行处理。可以在一个 catch 代码块中再次抛出异常。注意再次抛出异常需要try{}catch{},不能直接在catch代码块中throw异常

     脚本应该对用户隐藏系统错误。对程序员来说,系统错误也许很重要,但是用户对它们并不感兴趣。为了让用户更容易使用,您可以再次抛出带有对用户比较友好的消息的异常。
     简而言之:如果抛出了异常,就必须捕获它。

1.4.4 错误与异常的区别

异常:程序运行与预期不太一致错误:触发的是本身的错误
  • 当遇到错误的时候,触发的是本身的错误,不会自动的抛出异常。异常可以通过throw语句抛出异常,通过catch捕获异常,如果未捕获会产生致命错误。

    小微助手
    小微助手

    微信推出的一款专注于提升桌面效率的助手型AI工具

    下载
  • 错误在发生的时候或触发的时候,必须马上对脚本进行处理。异常可以一一向上传递,直到被捕获,再处理。

  • 错误触发不具有相关代码或名称。异常可以自定义处理错误信息(异常的好处就体现出来了),是通过代码来抛出,捕获然后处理

二、自定义异常类

2.1 自定义异常类

  1. 自定义异常类只能重写构造函数和toString两个函数

  2. 自定义异常类可以增加自己的方法

  3. 多个catch 时,一般Exception基类放在最后,基类可以调用自定义异常类定义的方法

/**
 * 自定义异常类
 * Class MyException
 */
class MyException extends Exception
{
    public function __construct($message = "", $code = 0, Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);
    }
    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...');
    }
    //自定义其它方法
}

try{
    echo '出现异常啦';
    throw new MyException('测试自定义异常');
}catch (MyException $exception){
    echo $exception->getMessage();
    echo $exception;
}
//会继续执行
echo 'continue.........';
try{
    throw new MyException('测试自定义异常');
}catch (Exception $exception){
    echo $exception->getMessage();
    $exception->test();
} catch (MyException $exception){
    echo $exception->getMessage();
}

2.2 小技巧

//将错误用错误抑制符吸收,然后抛出异常
If(@!fwrite($filename,$data)) throw new exception(自定义异常)

PHP_EOL #换行符

     记录错误日志信息方式:

     (1) :file_put_contents(LOG_PATH.'error.log';, '错误信息'.' '.date('Y-m-d H:i:s')."\r\n", FILE_APPEND);

     (2) :error_log('错误信息'.' '.date('Y-m-d H:i:s')."\r\n",3,LOG_PATH.'error.log');

2.3 使用观察者模式处理异常信息

Exception_Observer.php

/**
 * 给观察者定义规范
 *
 * Interface Exception_Observer
 */
interface Exception_Observer
{
    public function update(Observable_Exception $e);
}
Observable_Exception.php

/**
 * 定义观察者
 * Class Observable_Exception
 */
class Observable_Exception extends Exception
{
    //保存观察者信息
    public static $_observers = array();
    public static function attach(Exception_Observer $observer)
    {
        self::$_observers[] = $observer;
    }
    public function __construct($message = "", $code = 0, Throwable $previous = null)
    {
        parent::__construct($message, $code, $previous);
        $this->notify();
    }
    public function notify()
    {
        foreach (self::$_observers as $observer) {
            $observer->update($this);
        }
    }
}
Logging_Exception_Observer.php

/**
 * 记录错误日志
 * Class Logging_Exception_Observer
 */
class Logging_Exception_Observer implements Exception_Observer
{
    protected $_filename = __DIR__.'/error_observer.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',time()).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);//写到日志中
    }
}
test.php

/**
 *测试
 */
header('content-type:text/html;charset=utf-8');
require_once 'Exception_Observer.php';
require_once 'Logging_Exception_Observer.php';
require_once 'Observable_Exception.php';

Observable_Exception::attach(new Logging_Exception_Observer());

class MyException extends Observable_Exception{
    public function test()
    {
        echo 'this is a test';
    }
}

try{
    throw new MyException('出现了异常!');
}catch (MyException $exception){
    echo $exception->getMessage();
}

三、自定义异常处理器

3.1 如何自定义异常处理器

3.1.1 自定义异常处理器

  1. 类似set_error_handler接管系统的错误处理函数,set_exception_handler接管所有没有被catch的异常

  2. restore_exception_handlerrestore_error_handler一样,本质上应该说从异常/错误处理函数栈中弹出一个。比如有一个异常处理函数,弹出一个的话,就没有异常处理函数,如果有异常没有捕获,会交由错误处理函数,如没有错误处理函数,异常最终会有系统错误处理函数处理。如果设置了2个异常处理函数,弹出一个,会交由下面一个异常处理函数处理。

/**
 * 自定义异常函数处理器
 */
header('content-type:text/html;charset=utf-8');
function exceptionHandler_1($e)
{
    echo '自定义异常处理器1<br/>函数名:'.__FUNCTION__.PHP_EOL;
    echo '异常信息:'.$e->getMessage();
}
function exceptionHandler_2($e)
{
    echo '自定义异常处理器2<br/>函数名:'.__FUNCTION__.PHP_EOL;
    echo '异常信息:'.$e->getMessage();
}

set_exception_handler('exceptionHandler_1');
//set_exception_handler('exceptionHandler_2');
//恢复到上一次定义过的异常处理函数,即exceptionHandler_1
//restore_exception_handler();
//致命错误信息
//restore_exception_handler();
throw new Exception('测试自定义异常处理器');

//自定义异常处理器,不会向下继续执行,因为throw之后不会再继续执行;try{} catch{}之后,会继续执行
//回顾:自定义错误处理器会继续执行代码,而手动抛出的错误信息不会继续执行
echo 'test';
/**
 * 自定义异常类处理器
 * Class ExceptionHandler
 */

class ExceptionHandler
{
    protected $_exception;
    protected $_logFile = __DIR__.'/exception_handle.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);
    }

    /**
     * 魔术方法__toString()
     * 快速获取对象的字符串信息的便捷方式,直接输出对象引用时自动调用的方法。
     * @return string
     */
    public function __toString()
    {
        $message = <<<EOF
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
            <h1>出现异常了啊啊啊啊</h1>
        </body>
        </html>
EOF;
    return $message;
    }

}
set_exception_handler(array('ExceptionHandler','handle'));
/**
 * try catch不会被自定义异常处理!!!!
 */
try{
    throw new Exception('this is a test');
}catch (Exception $exception) {
    echo $exception->getMessage();
}
throw new Exception('测试自定义的异常处理器');

3.1.2 错误/异常之后是否继续执行代码问题总结

异常:

自定义异常处理器不会向下继续执行,因为throw之后不会再继续执行
try{} catch{}之后,会继续执行

错误:

自定义错误处理器会继续执行代码,而手动抛出的错误信息不会继续执行

3.2 像处理异常一样处理PHP错误

3.2.1 方式一:ErrorException

/**
 * 方式一:ErrorException错误异常类
 * @param $errno
 * @param $errstr
 * @param $errfile
 * @param $errline
 * @throws 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 $exception){
    echo $exception->getMessage();
}

3.2.2 方式二:自定义异常类,继承基类Exception

/**
 * 方式二:自定义异常类
 * Class ErrorToException
 */
//显示所有的错误
error_reporting(-1);
class ErrorToException extends Exception{
    public static function handle($errno,$errstr)
    {
        throw new self($errstr,0);
    }
}

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

try{
    echo $test;//notice,不会被处理
    echo gettype();//warning
    //手动触发错误
    trigger_error('test',E_USER_WARNING);
}catch (Exception $exception){
    echo $exception->getMessage();
}

3.3 PHP页面重定向实现

header('Content-type:text/html;charset=utf-8');
class ExceptionRedirectHandler{
    protected $_exception;
    protected $_logFile = __DIR__.'redirect.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();
        // ob_end_clean()清除所有的输出缓冲,最后没有缓存的时候会产生通知级别的错误
        while(@ob_end_clean());
        header('HTTP/1.1 307 Temporary Redirect'); //临时重定向
        header('Cache-Control:no-cache,must-revalidate');//no-cache强制向源服务器再次验证,must-revalidate可缓存但必须再向源服务器进行确认
        header('Expires: Sat, 28 Mar 2016 13:28:48 GMT'); //资源失效的时间
        header('Location:'.$self->redirect); //跳转
    }
    public function log(){
        error_log($this->_exception->getMessage().PHP_EOL,3,$this->_logFile);
    }
}
set_exception_handler(array('ExceptionRedirectHandler','handle'));
$link=@mysqli_connect('127.0.0.1','root','1234561');
if(!$link){
    throw new Exception('数据库连接出错啦');
}

完!

参考课程视频:那些年你遇到的错误与异常

相关推荐:

PHP程序员遇到的错误与异常上篇之错误

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

493

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

382

2023.10.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

448

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

606

2023.08.10

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

76

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

116

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

347

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

63

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

109

2026.03.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号