异常(转)

php--异常

PHP应该什么时候使用 Exception ? 它的性能如何?

这个问题也算是一个久经争论的经典问题了. 我谈谈我的个人看法.

异常与之对应的错误码(或者状态码), 到底各自有什么优点, 缺点, 我们应该怎么使用呢?

错误码

首先来说, 异常机制是在错误码机制之后才出现的, 那么根据进化论, 异常自然是避免了错误码机制的一些不足. 这些不足包括.

1. 错误信息不丰富

函数, 只能有一个返回值(当然, Lua可以返回多个, 但其实也相当于在PHP中返回一个数组), 我们见过最多的函数说明就是: 成功时候返回***, 错误的时候返回FALSE, 然而一个函数出错我原因可能有多种, 出错的种类更有多种. 一个简单的FALSE, 并不能把具体的错误信息告诉调用者.

于是, 我们也就见过一些, 这样的函数说明: 如果返回值大于0, 则表示成功的状态码, 如果返回值小于0, 则表示出错的状态码.

然而, 这个要求函数是返回整形(或者数字), 对于一些其他函数, 我们并不能通过0, >0, <0来判别, 并且, 即使通过这样的方式, 我们还需要用返回的错误码和一些预定义宏(或者调用类似strerror())来获取具体的, 可读的错误信息.

于是, 就有一些函数使用全局的错误码, 和错误信息, 来保存具体的错误信息, 这个时候我们就看到这样的函数描述: 成功返回***, 出错的时候返回FALSE, 错误代码保存在全局变量$errno中(至少大多数Linux库函数是这样描述的, 呵呵).

Okey, 这样的方式确实可以工作, 但是, 是不是觉得, 很丑陋呢?

2. 加入错误状态码可能需要改变函数签名

假设, 你编写了一个函数, 这个函数很简单, 很简单, 你认为他绝对不会出错, 于是你申明为(用C语言为例, PHP没有返回类型提示):

  1. void dummy() {
  2. }

但是后来你慢慢修改了这个函数, 给了它更多的功能, 此时这个函数可能会失败了. 而你现在根本无法为这个函数, 加入错误返回码了.

也许有人说PHP没有返回值类型限制一说, 但是想想PHP的构造函数, 构造函数是没有返回值的, 当发生错误的时候, 如果你不使用异常, 我想你只能选择die, 或者使用2中的方法来错误继续执行了.

另外, 在一个良好的软件系统中, 返回类型其实也是约定俗成的, 当所有的使用的函数的地方, 都没有检查返回值的时候, 你还是无法为这个函数加入错误返回码.

3. 错误状态码可能会被忽略

当你的一个函数, 出错了, 返回了错误状态码, 而调用方并没有检测这个返回值, 会发生什么情况呢? -_#. 令一方面, 处处检测返回状态码, 会造成代码非常的,,ugly:

  1. <?php
  2. if (!call1()) {
  3. die();
  4. }
  5. if (call2() != SUCCESS) {
  6. die();
  7. }
  8. if (call3() < 0) {
  9. $msg = error_get_last();
  10. die($msg["message"]);
  11. }

异常机制

那么现在我们来看看异常机制, 如果我们采用异常机制, 上面的代码可以写作:

  1. <?php
  2. try {
  3. call1();
  4. call2();
  5. call3();
  6. } catch (Exception $e) {
  7. die($e->getMessage());
  8. }

更方便的, 如果你的代码只是中间层, 你的调用方会负责处理错误的话, 你甚至可以简单的写作:

  1. <?php
  2. function myFunc() {
  3. call1();
  4. call2();
  5. call3();
  6. }

而一个异常对象, 可以包含更丰富的错误信息, 比如错误信息, 错误码, 错误的行数, 文件, 甚至出错上下文, 等等, 避免的”1.错误信息不丰富”的不足.

我们也可以为一个返回void类型的函数增加异常, 而不改变他的函数签名, 也就不会有上面说的”2.加入错误状态码可能需要改变函数签名”. 对于PHP来说, 如果我们新加入的错误没有被捕捉, 也不用担心, 会明显的出错的. 也就不会发生上面所说的”3. 错误状态码可能会被忽略”的情况.

然而, 也有一些反对使用异常的声音:

1. 性能

正如文章开头提问中的: “它的性能如何?”, 异常机制确实要比返回状态码的方式昂贵一些, 对于C++来说, 在异常发生的时候, 还要发生堆栈解退(对于PHP来说, 没有这个逻辑, 具体的大家可以参看我之间写的一篇文章:深入理解PHP原理之异常机制).

性能和方便, 往往是一个矛盾体, 我只能说, 你需要权衡, 如果你写的是一个小的模块, 并且它的生命期可能很短, 也不需要什么特殊的设计模式, 那我觉得你可以不用异常.

而如果你在为一个庞大的软件做开发, 我想你更应该看重的, 应该是, 它的可扩展性, 可维护性.

2. 太多可能的Uncaught Exception

如果, 你调用了一个可能发生异常的函数, 但是却没有捕获这个异常, okey, Fatal Error了, 所以让我们的代码看起来:

  1. <?php
  2. try {
  3. } catch () {
  4. }
  5. ....
  6. try {
  7. } catch () {
  8. }
  9. ....
  10. try {
  11. } catch () {
  12. }

然而, 这个是可以经过良好设计避免的, 比如我在设计Yaf的时候, 就提供了全局异常处理, 也就是类似于, 你在最最顶层, 加上了一个try catch, 所有的异常错误逻辑都加到这个里面, 你也可以很方面的把你自己的异常加进去.

时间: 2024-10-10 03:40:46

异常(转)的相关文章

使用 IDEA 创建 Maven Web 项目 (异常)- Disconnected from the target VM, address: &#39;127.0.0.1:59770&#39;, transport: &#39;socket&#39;

运行环境: JDK 版本:1.8 Maven 版本:apache-maven-3.3.3 IDEA 版本:14 maven-jetty-plugin 配置: <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <configuration> <webAppSourceDirectory>${pro

mybaits非配置原因,导致SqlSession was not registered for synchronization异常

今天运行程序时报了 SqlSession [[email protected]] was not registered for synchronization because synchronization is not active [11:03:17]-Closing non transactional SqlSession [[email protected]] 由于异常是集中处理的,所以报了这样的错误,查了半天,网上结果都是说配置文件出错的,可是我的项目配置文件肯定是没错的,因为项目都开

异常笔记--java编程思想

开一个新的系列,主要记一些琐碎的重要的知识点,把书读薄才是目的...特点: 代码少,概念多... 1. 基本概念 异常是在当前环境下无法获得必要的信息来解决这个问题,所以就需要从当前环境跳出,就是抛出异常.抛出异常后发生的几件事: 1.在堆上创建异常对象. 2.当前的执行路径中止                                          3. 当前环境抛出异常对象的引用.                                         4. 异常处理机制接

爱上MVC~业务层刻意抛出异常,全局异常的捕获它并按格式返回

对于业务层的程序的致命错误,我们一直的做法就是直接抛出指定的异常,让程序去终断,这种做法是对的,因为如果一个业务出现了致命的阻塞的问题,就没有必要再向上一层一层的返回了,但这时有个问题,直接抛异常,意味着服务器直接500了,前端如何去显示,或者如果你是API的服务,如果为前端返回,如果是500,那直接就挂了,哈哈! 下面是在MVC环境下优化的全局异常捕获代码(非API) /// <summary> /// 全局异常捕获 /// </summary> public class Glo

Laravel 5.4 中的异常处理器和HTTP异常处理实例教程

错误和异常是处理程序开发中不可回避的议题,在本地开发中我们往往希望能捕获程序抛出的异常并将其显示打印出来,以便直观的知道程序在哪里出了问题并予以解决,而在线上环境我们不希望将程序错误或异常显示在浏览器中(出于安全考虑),这个时候我们仍然要捕获异常,只不过不是显示到浏览器中,而是记录到日志中,方便日后排查问题. 百牛信息技术bainiu.ltd整理发布于博客园 Laravel当然支持PHP原生的错误和异常处理,但是在此基础上进行了一些封装处理,从而更方便在不同开发环境切换以及对错误和异常的处理.

Java必知必会:异常机制详解

一.Java异常概述 在Java中,所有的事件都能由类描述,Java中的异常就是由java.lang包下的异常类描述的. 1.Throwable(可抛出):异常类的最终父类,它有两个子类,Error与Exception. Throwable中常用方法有: getCause():返回抛出异常的原因.如果 cause 不存在或未知,则返回 null. getMeage():返回异常的消息信息. printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值.

python 异常和弹出框

import tkinter.messagebox try: fileContent = open("abnormal.txt") fileContent.close() print("over") #把异常消息赋予一个"ex"变量 except Exception as ex: print(ex) tkinter.messagebox.showinfo("Alert",ex) tkinter.messagebox.askye

python基础--接口与归一化设计、封装、异常、网络编程

1 接口与归一化设计 1.1 归一化概念: 归一化的好处: 1.归一化让使用者无需关心对象的类是什么,只需要知道这些对象都具备某些功能就可以了,这极大降低了使用者的使用难度. 2.归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合 继承的两种用途 一:继承基类的方法,并且做出自己改变或者扩展(代码重用):实践中,继承的这种用途意义并不很大,甚至常常是有害的.因为它使得子类与基类出现强耦合. 二:声明某个子类兼容于某基类,定义一个接口类(模仿java的Interface),接口类中

异常上报工具:腾讯Bugly

1.腾讯出了一个和umeng差不多的异常上报工具Bugly.(传送门:https://bugly.qq.com/docs/) (1)两者比较明显的区别是,Bugly能比较实时上报异常信息,经过测试基本上几秒就能在后台看到上报的信息,umeng的要等一段时间:(这个是我选择Bugly的主要原因) (2)Bugly感觉比较轻盈,主要方向就是异常上报:umeng感觉比较臃肿,主要方向在后台数据统计上:(个人感觉) 2.Cocos的接入文档就在里面,提供了c++/lua/js三种方式的接入,很简单方便就

最近遇到的异常与错误总结

异常 NumberFormatException  数字格式化异常 ArithmeticException 算术异常 ArrayIndexOutOfBoundsException  数组超出绑定异常:没有输入参数,或输入的参数不够 NullPointerException 空指针异常:使用了未实例化的对象 NoSuchMethodError:main  找不到主方法 ClassCastExeption:A 类转换异常 IllegalThreadStateException:非法的线程状态异常 I