子类化异常

时间:2010-08-23 16:57:57

标签: php zend-framework exception exception-handling error-handling

我们都同意,为不同的任务使用不同的异常类型是可行的方法。

但是,我们最终会创建像这样的鬼文件:

/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Dojo
 * @subpackage View
 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Exception.php 20096 2010-01-06 02:05:09Z bkarwin $
 */

/**
 * @see Zend_Dojo_Exception
 */
require_once 'Zend/Dojo/Exception.php';

/**
 * @category   Zend
 * @package    Zend_Dojo
 * @subpackage View
 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Dojo_View_Exception extends Zend_Dojo_Exception
{
}

然后Zend_Dojo_ExceptionZend_Exception ...

相同

这个问题有没有通用方法?

throw new \My\Just\Declared\Exception\ (which extends \My\Just\Exception)之类的东西,所以我没有必须包装并要求所有这些鬼文件?

5 个答案:

答案 0 :(得分:7)

您似乎专注于这些“鬼”类的想法 - 没有实现的类或标记接口。坦白说,你错过了这一点。

在ZF1中,Exception类只是组件级别,该级别的所有异常都接收相同的异常类。这实际上只允许以下类型的捕获:

  • 全球水平(捕捉“例外”)
  • 组件级别(捕获组件级别异常)

这比在任何地方简单地抛出“例外”要好一点;你需要仔细检查异常消息,以了解出了什么问题。

现在,请仔细阅读提案。

提案的目的是在捕获异常时允许更多级别的粒度:

  • 不在乎它是什么例外? Catch \ Exception。
  • 寻找特定组件的例外情况,但不关心其他细节?抓住该组件的Exception接口。
  • 想要寻找特定类型的SPL例外吗?抓住那些(在ZF2中,异常类实现组件异常接口,并扩展适当的SPL异常)。
  • 想要捕获组件中的特定异常类型?抓住它。

基本上,我们现在只允许在 TYPE 异常上提供更大的粒度;如果您尝试的操作可能抛出多个相同类型的异常,则只需要检查消息。通常,情况并非如此。

SPL异常在语义上相当丰富,并且ZF中的许多异常将更好地归类为这些类型(例如,无效参数应该引发InvalidArgumentException;无法解析插件将是一个很好的RuntimeException;等等)。使用ZF1,这是不可能的 - 我们必须继承组件级异常,句点。通过移动到标记接口,我们既可以捕获组件级异常以及SPL级别,也可以获得更具体的异常类型。

答案 1 :(得分:1)

有些人使用autoloader即时创建例外。

答案 2 :(得分:1)

在良好实践中,并非真的...如果你真的想要这样做,你可以做一些黑客攻击,但我仍然认为它们更邪恶。

例如,其中一个黑客是eval这些类通过自动加载器存在。这很糟糕,因为如果有人grep用于例外的定义或者你的软件包抛出的异常,那么它们将会是一大堆nada的回报......

public static function load($name) {
    $parts = explode('_', $name);
    if (strtolower(end($parts)) == 'exception') {
        //make it extend the proper exception
        array_pop($parts); //get rid of the last Exception bit
        array_pop($parts);
        $parts[] = 'Exception';
        $parent = implode('_', $parts);
        $code = 'class '.$name.' extends '.$parent . '{}';
        eval($code);
    }
}

但是,请允许我强调这通常是一个坏主意。

就个人而言,我从多个“基本例外”(通常是SPL exceptions)继承。因此,例如Database_Connection_Exception可能会扩展RuntimeException,尝试提交非开放事务可能会抛出Database_Not_In_Transaction_Exception,这可能会扩展LogicException。关键是单独声明它们可以让你做的不仅仅是直接的heiarchal继承(更不用说文档更好了,因为人们可以看一眼定义的异常,你可以实际覆盖方法以更好地满足你的需求,如果合适的话)...

修改:根据您提到Zend每个子包执行一个例外的倾向,我就是这样做的...

基本上,我在整个应用程序中使用了一些“全局”异常。这些包括(但不限于):ClassNotFoundExceptionFileNotFoundExceptionNotCallableException和其他一些。基本上只是那些不是特定于包的,但需要传达比核心PHP异常更多的含义......

然后,我只在包级别声明异常。在该目录(package/exceptions)中,我根据需要声明了每个例外。因此,一个子包可能有5或10个例外来区分不同的条件,而另一个子包(在同一个包中)可能没有。所以我根据需要声明它们,以便异常意味着发生了什么。

我这样做的原因很简单。我不关心where异常被抛出(如果我真的这样做,我可以检查在异常内部自动生成的回溯)。我关心why异常被抛出。这让我能够正确处理异常......

答案 3 :(得分:0)

从我的观点来看,异常是或者应该只在开发模式中可见。生产模式不应显示用户/客户端的异常,而是显示“遇到问题”或类似内容的简单页面。应该记录这些例外情况。最重要的是,它们主要用于调试或在必要时控制执行流程(当它们是预期的时候)。您可以简单地抛出Zend_Exception,但这只会使您的异常过于通用,并且很难在try..catch中找到原因

我通常创建 ghost文件 - 就像你调用它们一样 - 主要是在“包”级别上,或者当一个方法被抛出异常时(所以我可以抓住它)例外并因此对待它。)

您最终可能会得到许多 ghost文件,但这样只会使您的项目更有条理,最终也很容易调试。由于这些例外仅在需要的基础上加载,因此拥有大量例外不会影响性能。

答案 4 :(得分:0)

事实上,PHP已经有异常子类,有关完整列表,请参阅here。因此,关于其使用的文档非常有限,您可以查看this post on php exceptions以获取每个文档的含义。