当前位置: 美高梅集团手机版 > 美高梅集团 > 正文

在遇到无法修复的状况时抛出,这些特性中的一

时间:2020-02-05 16:12来源:美高梅集团
每一个新的功能添加到PHP运行时会创建一个指数随机数,通过这样的方式开发者可以使用和甚至滥用这个新特性。然而,直到一些好的和坏的使用情况陆续出现开发者们才达成了共识。

每一个新的功能添加到PHP运行时会创建一个指数随机数,通过这样的方式开发者可以使用和甚至滥用这个新特性。然而,直到一些好的和坏的使用情况陆续出现开发者们才达成了共识。当这些新案例不断浮现,我们终于可以辨别出什么是最好或最坏的做法。

异常

1).异常是Exception类的对象,在遇到无法修复的状况时抛出,例如远程API没有响应或者数据库查询失败再或者是无法满足程序运行的前置条件。出现问题的时候异常用于主动出击,委托职责;异常还可以用于防守,预测潜在的问题来减轻影响。2).Exception对象和其他的PHP对象一样,使用new关键字实例化。

<?php$exception = new Exception('userId cannot be null', 100);

第一个参数是消息,第二个参数是数字代码。数字代码是可选的,用于为指定的异常提供上下文。我们可以使用公开的实例方法getCodegetMessage来获得异常对象的两个属性。3).假如遇到了异常情况,或者在当前的条件下无法操作,我们需要抛出异常。

<?phpthrow new Exception('Something went wrong.Time for lunch!');

4).我们必须抛出Exception类或者他的子类,PHP内置的异常类和其子类如下:

  • Exception
  • ErrorExceptionPHP标准库提供了下述额外的Exception子类,扩展了PHP内置的异常类。
  • LogicException
  • BadFunctionCallException
    • BadMethodCallException
  • DomainException
  • InvalidArgumentException
  • LengthException
  • OutOfBoundsException
  • RuntimeException
  • OutOfBoundsException
  • OverflowException
  • RangeException
  • UnderflowException
  • UnexpectedValueException

5).捕获异常。预测和捕获并处理异常是我们自己的责任,因为未捕获的异常可能会导致PHP应用终止运行,显示错误信息。拦截并处理潜在异常的方式是,把可能抛出异常的代码放在在try/catch块中。

try { $pdo = new PDO('mysql://host=wrong_host;dbname=wrong_name');} catch (PDOException $e) { $code = $e->getCode(); $message = $e->getMessage(); echo 'Something went wrong.Check back soon, please'; exit;}

还可以连续抛出多个异常

try { throw new Exception('Not a PDO exception'); $pdo = new PDO('mysql://host=wrong_host;dbname=wrong_name');} catch (PDOException $e) { echo 'Caught PDO exception';} catch (Exception $e) { //处理其他异常 echo 'Caught generic exception';} finally { //这里的代码始终都会执行 echo 'Always do this';}

捕获某种异常的时候只会允许其中一个catch块,如果PHP没有找到适用的catch块,异常会向上冒泡,直到PHP脚本由于致命的错误而终止。6).异常处理程序。我们可以使用一个全局的异常处理程序,来捕获所有未被捕获的异常。异常捕获程序都必须接受一个了类型为Exception的参数,异常捕获程序使用set_exception_handler()函数注册。

<?phpset_exception_handler(function (Exception $e) { //处理并记录异常});//你的代码...//还原成之前的异常处理程序restore_exception_handler();

异常处理在PHP中的确无论如何都不算是一个新的特征。但在本文中,我们将讨论在PHP 5.3中基于异常处理的两个新的特点。第一个是嵌套异常第二是一套SPL的扩展的新的异常类型。这两个新特性,这本书里都能找到最佳实践值得各位去详细研究。

错误

1).我们可以使用error_reporting()函数或者在php.ini文件中使用error_reporting指令告诉PHP报告或者忽略那些错误。这两种都是使用E_*常量来确定。2)错误报告方式四原则:

  • 一定要让PHP报告错误
  • 在开发环境中要显示错误
  • 再生产环境中不能显示错误
  • 在开发和生产环境中都要记录错误

3)一种php.ini配置的例子:开发环境:

;显示错误display_startup_errors = Ondisplay_errors = On;报告所有错误error_reporting = -1; 记录错误log_errors = On

生产环境:

;不显示错误display_startup_errors = Offdisplay_errors = Off;除了注意事项外,报告所有错误error_reporting = E_ALL & ~E_NOTICE; 记录错误log_errors = On

4).注册全局的错误处理程序:set_error_handler()函数。

<?phpset_error_handler(function($errno, $errstr, $errfile, $errline) { //处理错误 //$errno表示错误等级对应E_*常量 //$errcontext是一个省略的参数,高级调试才用到});

5.一个简单的全局错误处理程序的例子:

set_error_handler(function($errno, $errstr, $errfile, $errline) { if (!(error_reporting() & $errno)) { //error_reporting指令没有设置这个错误,所以忽略 return; } throw new ErrorException($errstr, $errno, 0, $errfile, $errline);});//其他代码//还原成之前的错误处理程序restore_error_handler();

特别要注意:这些特性中的一些已经存在于低于5.3的PHP版本之中,或者至少能够在低于5.3的版本之中被实现. 而当本文提到 PHP 5.3, 并不是严责意义上的 PHP 运行时版本. 相反,它意味着代码库和项目是采用 PHP 5.3 作为最低版本的,但同时也是在新的发展阶段出现的所有最佳实践. 这个发展阶段所凸显的是特定的几个像Zend Framework, Symfony, Doctrine 以及 PEAR 这样的项目所进行的“2.0”尝试.

相关处理组件
  • 开发环境: filp/whoops
  • 生产环境: monolog/monolog

PHP专题系列目录地址:

背景

PHP 5.2 只有一个异常类 Exception。按照 Zend Framework / PEAR 的开发标准, 这个类是你的库中所有异常类的基类。如果你创建一个名叫 MyCompany 的库,按 Zend Framework / PEAR 的标准, 库中所有的代码文件都会以 MyCompany_ 开头。要是你想给库创建自己的异常基类: MyCompany_Exception, 那就用该类继承 Exception,然后再由组件继承和抛出该异常类。比如你有一个组件 MyCompany_Foo,你可以给它创建一个用在该组件内部的异常基类 MyCompany_Foo_Exception。这些异常能被捕捉 MyCompany_Foo_Exception,MyCompany_Exception 或 Exception 的代码捉到。 对于库中其他用到该组件的代码来说,这是个三层的异常(或更多,取决于 MyCompany_Foo_Exception 的子类有几层 ), 他们可以根据自己的需要处理这些异常。

在php5中,基本异常类已经支持嵌套的特性了。什么是嵌套呢?嵌套是一种能力可以去捕获特殊异常,或者捕获参照原始异常而创建的一个新的异常对象。这将会允许caller属性在更公开的类型的开销库中出现的两种异常类上得到体现,当然也会在具有原始异常行为的异常类上体现。

为什么这些特性很有用?通常,通过使用其他代码来抛出自己的类型的异常是最有效的代码。这些代码可能是使用适配器模式封装的提供一些适应性更强强的函数的第三方代码库的代码,或利用一些PHP扩展来抛出异常的简单代码。

例如,在组件 Zend_Db 中, 它使用了适配器模式来封装特定的 PHP 扩展,来创建一个数据库抽象层. 在一个适配器中, Zend_Db 封装了 PDO, 而 PDO 会抛出它自己的异常 PDOException, Zend_Db 需要捕获这些特定于 PDO 的异常,并让它们以可预期且类型已知的 Zend_Db_Exception 重新被抛出. 这样就给了开发者保证, Zend_Db 将总是抛出 Zend_Db_Exception 类型的异常, 而他们同时也可以在需要的时候访问到最开始被抛出的 PDOException.

下面的示例展示了一个虚构的数据库适配器可能如何去实现嵌入式的异常:

class MyCompany_Database{ /** * @var PDO object setup during construction */ protected $_pdoResource = null; /** * @throws MyCompany_Database_Exception * @return int */ public function executeQuery { try { $numRows = $this->_pdoResource->exec; } catch  { throw new MyCompany_Database_Exception('Query was unexecutable', null, $e); } return $numRows; } }

为了使用嵌入式的异常,你就得调用被捕获异常的getPrevious()方法:

// $sql and $connectionParameters assumedtry { $db = new MyCompany_Database('PDO', $connectionParams); $db->executeQuery;} catch (MyCompany_Database_Exception $e) { echo 'General Error: ' . $e->getMessage() . "n"; $pdoException = $e->getPrevious(); echo 'PDO Specific error: ' . $pdoException->getMessage() . "n";}

大多数最近被实现的PHP扩展都拥有OO接口. 因此,这些API倾向于抛出异常,而不是发生错误终止。PHP中能够抛出异常的扩展,稍微列举出几个就包括有PDO, DOM, Mysqli, Phar, Soap 以及 SQLite.

新特性:新核心异常类型

在PHP 5.3开发中,我们展示了一些有趣的新异常类型。这些异常在PHP 5.2.x中已经存在,但最近还没到“重新评估”异常的最佳实践,现在他们会显得更加引人注目。他们在SPL扩展中得以应用,并在手册中列出由于这些新的异常类型是PHP核心的一部分,也是SPL的一部分,它们可以被任何用PHP 5.3运行代码的人使用。虽然在编写应用程序层的代码时,看起来不那么重要,但在我们写或者使用代码库时,使用这些新异常类型变得更加重要

那么为什么新异常是普通类型?以前,开发者试图通过在异常消息提醒中放入更多的内容来赋予异常更多的含义。虽然这样做是可行的,但是它有几个缺点。一是你无法捕获基于消息的异常。这可是一个问题,如果你知道一组代码是同样的异常类型与不同的提示消息对应不同异常情况下,处理起来的难度将相当的大。例如,一个认证类,在对$auth->authenticate,但不同的消息对应两个具体的故障:产生故障原因是认证服务器不能达到但是相同的异常类型却提示失败的验证消息不同。在这种情况下(注意,使用异常可能不是处理认证响应最好的方式),这将需要用字符串来解析消息从而处理这两种不同的情况。

这个问题的解决办法显然是通过某种方式对异常进行编码,这样就可以在需要辨别如何对这种异常环境做出反应的时候能够更加容易的查询到。第一个反应库是使用异常基类的$code属性。另一个是通过创建可以被抛出且能描述自身行为的子类或者新的异常类。这两种方法具有相同的明显的缺点。两者都没有呈现出想这样的最好的例子。两者都不被认为是一个标准,因此每个试图复制这两种解决方案的项目都会有小的变化,这就迫使使用这需要回到文档以了解所创建的库中已经有的具体解决方案。现在通过使用SPL的新的类型方法,也称作php标准库;开发者就可以以同样的方式在他们的项目中,并且复用这些项目的新的最佳的方法已经出现。

第二个缺点是使用详细信息的做法使得理解这些异常情况对那些非英语或英语能力有限的开发者来说十分困难。这可能会使的开发者在试图理解异常信息的含义的过程十分的缓慢。许多开发者也会写关于异常的文章,因为还未出现一个统一的整合过的标准所要有同这些开发者数量相同的不同的版本来描述异常消息所描述的情况。

编辑:美高梅集团 本文来源:在遇到无法修复的状况时抛出,这些特性中的一

关键词: