Laravel Exception处理逻辑解析

vendor/laravel/framework/src/Illuminate/Foundation/Application.php

  1. app首先继承了container,作为一个容器类存在
  2. 注册了laravel运行过程的需要的基础类进容器,并且生成了运行需要的实例。承担了初始化功能。这里需要额外说一下,app里面说的所谓注册,不是指绑定,应该是直接直接实例化了,并注入到容器。但是,针对provider,实例化了provider,并运行了,并不会生成实际的类,而是将类绑定。

ExceptionHandler的注册就是在Application的__construct方法中。

$this->registerErrorHandling();

接着我们来到定义该方法的trait:RegistersExceptionHandlers找到该方法。看一下该方法实现了什么样的逻辑。便于理解我加上了一些注释。

protected function registerErrorHandling()
{
error_reporting(-1);//-1报告所有异常,包括后续新定义的异常级别,作用与E_ALL相同 /** set_error_handler,set_exception_handler,register_shutdown_function分别注册不同级别不同类型异常的处理方法。 */ set_error_handler(function ($level, $message, $file = '', $line = 0) {
if (error_reporting() & $level) {
throw new ErrorException($message, 0, $level, $file, $line);
}
});//代替标准错误处理方法 set_exception_handler(function ($e) {
$this->handleUncaughtException($e);
});//兜底异常处理方法注册 register_shutdown_function(function () {
$this->handleShutdown();
});//注册一个在脚本正常或非正常情况终止执行时调用的方法。(终极兜底)
}

我们看到laravel主要通过三个原生方法来实现主要的ExceptionHandler机制。下面我们分开看一下这里都分别注册了哪些函数。

set_error_handler

function ($level, $message, $file = '', $line = 0) {
if (error_reporting() & $level) {
throw new ErrorException($message, 0, $level, $file, $line);
}
}

这块很简单,set_error_handler注册的函数会代替原生的报错处理逻辑。这里可以看到laravel将执行error作为异常抛出。并且保留了error的主要信息。(level,msg,file,line)

set_exception_handler

/**set_exception_handler(function ($e) {
$this->handleUncaughtException($e);
});**/ protected function handleUncaughtException($e)
{
//从容器中实例化一个真正的handler。(使用make方法)
$handler = $this->resolveExceptionHandler();
//如果获取到的是Error,通过Error信息实例化一个已定义的“可抛出的致命错误”
if ($e instanceof Error) {
$e = new FatalThrowableError($e);
}
//记录日志(先判断是否报告)
$handler->report($e);
//render错误
if ($this->runningInConsole()) {
$handler->renderForConsole(new ConsoleOutput, $e);
} else {
$handler->render($this->make('request'), $e)->send();
}
}
  1. resolveExceptionHandler方法从容器中make了一个handler实例,从该方法可以找到laravel实现的handler方法。该方法会判断是否绑定抽象类型来判断使用开发者自行绑定的ExceptionHandler还是系统自带的。handler的作用只有一点,就是解析异常,并将异常处理成我们想要的,更加用户友好的方式展示。(++render方法,可以看“Laravel\Lumen\Exceptions\Handler”,该类实现了Laravel的ExceptionHandler接口,想要自定义异常输出的话也可以参考该类++)
  2. report和render方法都是handler中定义的,report会先进行判断,并根据判断结果决定是否记录log。render自然不必多说,formatexception info,并作为一个HTTP response输出。

register_shutdown_function

protected function handleShutdown()
{
if (! is_null($error = error_get_last()) && $this->isFatalError($error['type'])) {
$this->handleUncaughtException(new FatalErrorException(
$error['message'], $error['type'], 0, $error['file'], $error['line']
));
}
}

error_get_last()是5.2版本实现的方法,能够很好的配合的register_shutdown_function进行兜底处理。改善了需要自定义变量判断的方法。

error_get_last 返回了一个关联数组,描述了最后错误的信息,以该错误的 "type"、 "message"、"file" 和 "line" 为数组的键。

另外,该方法规定只有致命的错误才会启动。

Laravel Exception处理逻辑解析的更多相关文章

  1. Laravel Exception结合自定义Log服务的使用

    Laravel Exception结合自定义Log服务的使用 第一部分:laravel关于错误和异常的部分源码 第二部分:自定义异常的使用(结合serviceprovider monolog elas ...

  2. ZooKeeper(二):多个端口监听的建立逻辑解析

    ZooKeeper 作为优秀的分布系统协调组件,值得一探究竟.它的启动类主要为: 1. 单机版的zk 使用 ZooKeeperServerMain 2. 集群版的zk 使用 QuorumPeerMai ...

  3. Hystrix失败处理逻辑解析

    在上篇文章Hystrix工作流程解析中,我们整体介绍了Hystrix的工作流程,知道了Hystrix会在下面四种情况下发生降级: 熔断器打开 线程池/信号量跑满 调用超时 调用失败 本篇文章则介绍一下 ...

  4. laravel启动过程简单解析

    :first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,.1);border-radius:3px ...

  5. Spring 声明事务中transactionAttributes属性 + - Exception 实现逻辑

    下面是一段典型的Spring 声明事务的配置: <bean id=“baseTxProxy” lazy-init=“true”class=“org.springframework.transac ...

  6. laravel的启动过程解析

    laravel的启动过程,也是laravel的核心,对这个过程有一个了解,有助于得心应手的使用框架,希望能对大家有点帮助. 统一入口 laravel框架使用了统一入口,入口文件:/public/ind ...

  7. ZooKeeper(五):事务处理之更新数据逻辑解析

    通过前些文章,我们已经完全从整体架构和数据接入方面理解了ZK的前情工作.接下来,我们就来看ZK的正式工作吧. 本文以 setData /a data 这个命令作为出发点,来观察zk是如何处理来自客户端 ...

  8. 随便聊聊 SOA & SOAP & WebService 的一些东西,以及客户端开发的代码逻辑解析

    http://blog.csdn.net/hikaliv/article/details/6459779 一天的时间调通了一个 WebService 的 Java 端的 C/S.一个 Android  ...

  9. LARAVEL IOC容器 示例解析

    <?php class People { public $dog = null; public function __construct() { $this->dog = new Dog( ...

随机推荐

  1. Python程序的编写方式

    直接在Python的交互式环境编写代码 现在,了解了如何启动和退出Python的交互式环境,我们就可以正式开始编写Python代码了. 在写代码之前,请千万不要用“复制”-“粘贴”把代码从页面粘贴到你 ...

  2. BSOJ 2423 -- 【PA2014】Final Zarowki

    Description 有n个房间和n盏灯,你需要在每个房间里放入一盏灯.每盏灯都有一定功率,每间房间都需要不少于一定功率的灯泡才可以完全照亮.  你可以去附近的商店换新灯泡,商店里所有正整数功率的灯 ...

  3. MyBatis+Hibernate+JDBC对比分析

    MyBatis目前作为持久层,用的最多,因为它符合互联网开发的变动性,实际开发中需求总会有这样的,那样的变动,MyBatis虽然没有Hibernate那么全自动化,而且对于开发人员的sql能力要求比较 ...

  4. 20175105 2018-2019-2 《Java程序设计》第八周学习总结

    20175105 2018-2019-2 <Java程序设计>第八周学习总结 教材学习内容总结 第十五章主要内容有:泛型.链表.堆栈.散列映射.树集以及树映射. 泛型:可以使用class名 ...

  5. golang 转换markdown文件为html

    使用blackfriday go get -u gopkg.in/russross/blackfriday.v2 go: package markdown import ( "fmt&quo ...

  6. 安装Drush工具 -Centos

    Drush可以说是Drupal的瑞士***,只要你使用过一段时间的Drush,一但没有它的话,你会觉得很不方便.可如果通过我在前面博文中所讲的方法来安装Drush的话,是不能够支持Drupal8的,所 ...

  7. ORA-10858:在要求输入数字处找到非数字字符

    今天在写sql语句的时候,运行报错:ORA-10858:在要求输入数字处找到非数字字符 在网上查了一下为什么会有这种错误,有一个建议是可能是写的sql语句中的日期没有处理.仔细看了一下自己写的代码 就 ...

  8. 获取2个集合List<T>的共同元素

    获取2个集合List<T>的共同元素,循环2个集合,然后比对. class Bj { public void GetIntersect() { , , , , , , }; , , , , ...

  9. 把DataTable转换为List<T>

    前一篇有学习过<把List<T>转换为DataTable>http://www.cnblogs.com/insus/p/8043173.html 那此篇,将是学习反向,把Dat ...

  10. 解决微软surface pro在某些情况下wifi转输速度过慢的问题 - z

    我是新款i7 surface.昨天到的货,狗东. 在公司使用的时候网络很正常,但回到家里之后就特别卡.5G频段也特别卡,基本处于无法观看视频的地步.台式电脑(我台式用的无线网卡)和手机都没问题. 于是 ...