首页 > 解决方案 > 在 php 中扩展异常的逻辑问题

问题描述

对于 PHP,我使用以下类结构来处理异常:

class ProjectException extends Exception {
          ... logical code for handling exceptions, functions that are relevant to every exception my project throws go here
}

class SpecificException extends ProjectException {
     protected $codePrefix = 'SE';

     const ERROR_SOMETHING_BAD_HAPPENED              = 100;
     const ERROR_SOMETHING_SIMMILARLY_BAD_HAPPENED   = 101;

     /* no functions go in this class, this class is only to specify the code prefix of the exception, and the error codes used by it */
}

如果我想捕获异常,我通常使用以下类型的异常捕获:

 try {
    /** try something here **/
 } catch (SpecificException $e) {
    switch ($e->getCode()) {
       case SpecificException::ERROR_SOMETHING_BAD_HAPPENED:
         /** react to the exception based on it's code, and try to recover **/
       default:
         /** react to every unexpected code, which may appear if the tried function is modified,
             and throws a new exception code of the same type, and stop the execution of the 
             script, storing the error in the database **/
    }
 }

我的问题如下。我想“锁定”一些文件不被编辑,例如一些异常文件。我为什么要这样做,是因为我正在尝试使我的部分代码可移植,以便它可以用于我们正在处理的其他项目中。

我的想法是,稍后在新项目中,如果出现新的东西,并且应该制作新的异常代码,我将扩展“锁定”异常,并将新的错误代码编写为const扩展类中的 a。可能发生的现实生活场景是Account课堂。可移植代码中已经设计了一个裸Account类,具有登录和注册功能,但是在每个不同的项目中,这些帐户将获得项目特定的新功能。因此,在新项目中,我将扩展可移植项目Account类,并在那里编写相关功能。

从理论上讲,这是可行的,但我意识到,我认为以后管理这将是一个真正的痛苦,因为:

  1. 捕获异常时,我现在要么需要捕获父异常,以捕获每个抛出的异常,要么我必须编写两个(三个、四个等)单独的 catch 块,具体取决于我扩展原始父异常的次数
  2. 如果我捕捉到父异常,我不能只抛出所有代码,而不知道代码的来源(父类或子类)

基本上我将不得不为这些编写类似的 try catch 块:

try {
  /** some code to try **/
} catch (SpecificException $e) {
  /** this will catch everything that is SpecificException or SpecificExtendedException or SpecificDoubleExtendedException **/
  switch ($e->getCode()) {
      case SpecificException::ERROR_IN_SPECIFIC:
         /** do something **/
         break;
      case SpecificException::ERROR_TWO_IN_SPECIC:
         /** do something **/
         break;
      case SpecificDoubleExtendedException::ERROR_IN_SECOND_EXTENDED_EXCEPTION:
         /** do something **/
         break;
      default:
         /** as it was originally written **/
         break;
    } 
}

有人对我应该如何进行有任何想法吗?“锁定”一些可移植文件并将新的异常代码添加到这些“锁定”文件中定义的异常中最自然的方法是什么?

标签: phpexception

解决方案


您可以简单地在您的ProjectException类中添加这样的方法:

public function getCodeFor(string $name): int
{
  return (int)constant("static::ERROR_$name");
}

这使用constant辅助函数和static关键字来检索在调用该方法的对象的实际类中定义的常量。

然后你可以有你的try块,这将适用于任何类扩展SpecificException

switch ($e->getCode()) {
  case $e->getCodeFor('SOMETHING_BAD_HAPPENED'):
    /** do something **/
    break;
  case $e->getCodeFor('SOMETHING_SIMILARLY_BAD_HAPPENED'):
    /** do something **/
    break;
  case $e->getCodeFor('SOMETHING_SPECIFICALLY_BAD_HAPPENED'):
    /** do something **/
    break;
}

演示:https ://3v4l.org/sAQdE

注意:显然,使用字符串会使您失去 IDE 重构常量的能力。但是由于您无法提前知道哪些类将定义给定代码(或者您可以,但不希望必须这样做),所以这是一个合理的解决方法。

注意 2:可能有更好的方法来做设计方面的事情(正如@Barmar 指出的那样,询问软件工程可能更适合于架构讨论)。这个答案只是试图为您当前的问题提供编程解决方案,而不改变所述设计。


推荐阅读