《PHP精粹:编写高效PHP代码》——1.7节异常

1.7 异常
异常(exception)是一个处理错误的面向对象方法。一些PHP扩展像往常一样仍会报错;很多最新的扩展(例如PDO)将代替抛出异常。异常也是对象,而且Exception是PHP的一个内置类。一个Exception对象将包含发生错误的位置(文件名或代码行)、一条错误消息和(可选)一个错误代码等信息。

1.7.1 处理异常
首先我们看看如何处理可能会抛出异常的函数。我们会使用一个PDO示例,因为PDO扩展抛出异常。在这里代码会试图创建一个数据库连接,但是会失败,因为nonsense主机不存在:

这段代码阐明了try/catch结构。在try块中,我们将想要的代码放到应用程序中运行,但我们知道代码可能会抛出一个异常。在catch块中,可以添加一些应对错误的代码,无论是处理它还是记录它,采取任何行动都是恰当的。
注意,当发生一个异常时,就像这里试图连接到数据库一样,PHP没有运行try块中其余的代码而直接跳转到catch块中。在这个示例中,数据库连接失败意味着我们根本看不到已连接到数据库的消息,因为这一行代码根本无法运行。
无finally子句
如果你在其他语言中使用过异常,你可能习惯于try/catch/finally结构;PHP没有附加的finally子句。

1.7.2 为什么要处理异常
比起会引发不同层次错误的传统方法,异常是一个更简洁的错误处理方法。在执行代码的过程中,我们可以根据错误的严重程度对异常做出反应。我们可以对问题进行评估,然后告诉系统如何恢复,或顺利地摆脱困境。
将所有的异常作为对象意味着我们可以扩展异常(很快会有示例演示),并且可以自定义异常的数据和反应。我们已经知道如何使用对象工作,这使得我们能更简单地把复杂功能添加到错误处理系统中。

1.7.3 抛出异常
我们已经看到如何处理由PHP内置函数抛出的异常,但是我们自己如何抛出异常呢?是的,我们肯定能够做到这一点:

可根据需要为Exception类设置任何属性或添加任何方法。定义为一个空类也很常见,空类只是为了提供更多特定类型的异常,使我们识别出:应用程序的哪一部分遇到了问题而没有尝试以编程方式读取错误信息。
自动加载异常
此前,介绍了自动加载,为在哪里能找到类而定义规则,而在脚本中执行的代码并未包含这个类的定义。异常也是简单的对象,因此也可以使用自动加载功能来加载异常类。

通过所有特定的异常类可以捕捉不同的异常类型,将在下一节学习这一点。

1.7.5 捕捉特定类型的异常
思考如下这个代码示例可以抛出多个异常:

在这个示例中,开始实例化Courier和Parcel两个对象。Parcel对象既有地址又有重量;当发货的时候会检查它们。注意,这个示例使用了一个小小的rand()函数来产生各种包裹的重量!这是一个测试代码的有趣方法,因为有些包裹由于超重而引发异常。
在try块中,要求快递公司运送包裹。如果运气好,过程一切顺利,我们就会看到“parcel shipped”消息。这两个catch块让我们巧妙地处理失败结果,第一个catch块负责特定捕捉HeavyParcelException异常,任何其他类型的异常由第二个很普通的catch块捕捉。如果我们想首先捕捉Exception异常,所有的异常将最终在这里被捕捉,那么我们首先要保证这个catch块具有最特殊的异常类型。
实际上,这个catch块使用了类型提示来区分一个对象是否为可接受的类型。因此前面介绍的类型提示和多态性也适用于这里;一个HeavyParcelException异常也是一个Exception异常。
在这个示例中,异常从类的内部抛出,进而捕捉代码中调用对象方法的栈。没有捕捉到的异常会返回调用它的内容中,如果在这里它们仍然没有被捕捉,它们将继续通过调用栈向上抛出。当它们到达顶部仍然未被捕捉,我们将看到严重的错误:Uncaught Exception。

1.7.6 设定一个全局异常处理程序
为避免出现异常被抛出而代码捕捉失败的严重错误,可以为应用程序设定一个默认的行为。为做到这一点,使用了一个名为set_exception_handler()的函数。它接受一个回调作为它的参数,因此可以为使用的函数命名,例如,一个异常处理程序通常会在屏幕上给用户显示一个错误提示—这比一个严重错误的消息要好得多!
一个基本的异常处理程序类似于这样:

这里显示了一个异常处理程序,然后它调用set_exception_handler()方法注册这个函数来处理未捕获的异常。通常在脚本的开始部分声明和设置异常处理程序,或者放在引导文件中,如果你有一个的话。
默认错误处理
除了使用set_exception_hander()处理异常外,PHP也提供set_error_handler()方法处理错误。

示例异常处理程序使用error_log()函数在PHP的错误日志中写入错误的内容,打开日志文件会看到如下内容:

1.7.7 使用回调
刚才展示了回调函数的使用,正好我们可以看看是否还有其他可用的选择。回调广泛应用于PHP的各个方面,set_exception_handler()和set_error_handler()函数就是很好的例子。也可以使用回调,例如,在array_walk()这个函数中,要求PHP使用相同的操作,为一个数组中的每一个元素指定使用一个回调。
回调可以使用多种形式:
一个函数名
一个类名和一个方法名,其中方法是静态调用的
一个对象和一个方法名,其中调用的方法与提供它的对象相对应
一个closure(存储在变量中的一个函数)
一个lambda函数(就地声明的一个函数)
回调让我们使用匿名函数成为可能。为异常处理程序声明的匿名函数不会用于应用程序的任何其他地方,因此没必要为它取一个全局性的名称。在PHP手册的相关页面上还有更多关于匿名函数的内容。

时间: 2017-08-01

《PHP精粹:编写高效PHP代码》——1.7节异常的相关文章

《PHP精粹:编写高效PHP代码》——2.8节数据库—排序

2.8 数据库-排序 在本章,我们全面讲述了与PHP开发者息息相关的数据库主题.了解了PDO扩展并利用它在你的应用程序中建立稳定高效的代码. 除PHP外,我们还研究了一连串的数据库技术,这些技术以不同的方式在表中建立SQL查询.我们还使用索引,设计了经受住时间和可扩展性考验的数据库架构.

《PHP精粹:编写高效PHP代码》——3.3节数据格式

3.3 数据格式 在许多方面,Web服务仅仅只是一个网页,它提供机器可读的内容,而不是人类可读的内容.我们与其在一个浏览器的HTML网页标记标签,不如返回内容到JSON或XML中(我们马上将论及上述内容). 健壮性Web服务的强大特征之一便是它的设计可使其以不同的格式返回信息.因此,如果一个服务消费者更喜欢另一种数据格式,它可以轻易请求到最好的格式.这表明,当我们创建的服务公开后,解释请求和构成响应的方式是独立于代码中其他部分的. 接下来的两节将详细讲解JSON和XML,并举例说明如何以这种方式

《PHP精粹:编写高效PHP代码》——1.8节更多神奇的方法

1.8 更多神奇的方法 本章已介绍了一些神奇方法.在表1.1中快速回顾一下这些方法. 当在一个类中定义这些函数时,可以定义当这些事件发生时会引发什么.没有这些函数的话,类将显现为默认行为,而这些常常都是需要的.PHP另外还有一些神奇方法,在本节中我们将看到一些使用最频繁的方法. 1.8.1 使用__call()和__callStatic()方法 在关于访问修饰符的内容里,我们看到,对于__get()和__set()方法而言,__call()方法是一个天生的搭档.使用__get()和__set()

《PHP精粹:编写高效PHP代码》——3.4节HTTP:超文本传输协议

3.4 HTTP:超文本传输协议HTTP(HyperText Transfer Protocol)是通过导线来传送Web请求和响应的数据传输格式.它包含了很多请求和响应的元数据,除了这些请求或响应的实体之外,我们也可以利用它来使用Web服务.我们也将看到其他的协议,例如XML-RPC和SOAP,它们也都是建立在HTTP基础上的.当我们在本章快结尾构建RESTful服务时,便可以广泛使用HTTP的功能了.当我们开发一个简单的Web应用程序时,可能不会那么重视HTTP.但是如果你想了解缓存.不同文件

学习PHP精粹,编写高效PHP代码之质量保证

一.使用静态分析工具测量质量   我们用静态分析测量代码而不运行它.实际上,我们将这些工具用于评估代码.读取文件.衡量它所写的要素.使用这些工具,可以帮助我们对代码库有一个完整的层次化的认识,甚至在代码库变得更大.更复杂的时候也能掌握.   静态分析工具是项目过程中的一个关键组成部分,但是,只有定期使用它们,并以理想的方式进行每一次提交,静态分析工具才真正显示出价值.这些工具涵盖了代码的所有方面,从计数类和计算行数,到识别哪里有提示使用复制和粘贴的类似代码段.然后我们来看看静态分析工具在代码质量

《PHP精粹:编写高效PHP代码》——2.4节PHP数据库对象

2.4 PHP数据库对象 如果之前你使用过PHP和MySQL,你可能用过mysql或mysqli类库连接到数据库,如使用mysql_connect()函数.多年来,这是连接到MySQL数据库的标准方式,并且对于其他数据库平台也使用同样的方式. 这些类库可以直接使用,并形成了无数PHP应用程序类库和框架的基础.这种方式的缺点是每个扩展都与其他稍有不同,因此使得代码在数据库平台之间轻松转移变得复杂.虽然这些数据库特定类库依然活跃并且运转良好,但是本章中仍将专注讲解更先进的PDO扩展.创建的PDO扩展

《PHP精粹:编写高效PHP代码》——2.6节处理PDO中的错误

2.5 处理PDO中的错误 当你刚开始使用PDO时,它的某个方面是令人惊讶或让人沮丧的(视你的态度而定),即当它出现问题时,并不总是显而易见的.当我们第一次连接到数据库时,就会看到一个失败的连接会导致抛出一个异常.这里有一个提醒的代码: 一般来说,当某些引人注目的事情发生时PDO会抛出异常,但是如果你的查询由于某些原因而未能运行时,你也不必为此大惊小怪.这表明我们要仔细检查一切是否按照我们所预期的那样运行. 让我们复习一下迄今为止所学到的相关内容,看看我们如何对出现的问题进行识别和反应. 2.5

《PHP精粹:编写高效PHP代码》——2.6节高级PDO特征

2.6 高级PDO特征 我们已经看到PDO功能构成了以数据库驱动的PHP应用程序的主体.然而, PDO还有几个锦囊妙计需要我们好好研究.下面两节将显示我们如何利用数据库的事务,以及如何在PHP代码中调用存储过程. 2.6.1 事务和PDO 在数据库术语中事务(transaction)是一组必须执行的语句的集合.这组语句要么必须全部顺利完成,要么一个也不运行.不是所有的数据库都支持事务,有些支持,有些不支持,有些经过配置以后才会支持.对于MySQL,有些表的类型难以获得事务支持. 如果数据库不支持

《PHP精粹:编写高效PHP代码》——1.2节OOP简介

1.2 OOP简介 开始冒险吧!在理论知识方面,我们会结合代码示例来讲解,这让你更容易看懂代码的实际意义. 1.2.1 声明类 类相当于蓝图,是表明如何创建对象的一组指令.它还不是一个对象,而仅仅是对象的一个描述.在Web应用程序中,用类来表示各种实体.下面是一个可能用于电子商务应用程序中的Courier类: 以上代码表明了如何声明类,可以将Courier类保存在一个名为courier.php的文件中.这个文件的命名方法是需要牢记的一个要点,其重要性在1.3节中会详细阐述,我们会讲解当需要时如何