使用自定义ID和自定义消息在PHP中处理错误

使用自定义ID和自定义消息在PHP中处理错误,php,class,error-handling,Php,Class,Error Handling,我正在进行一个项目,我不想直接向用户抛出错误。相反,我想要定制的错误消息accur 以后我还需要保留一个错误号,以便自定义来自类外部的错误消息,如错误消息数组 所以我做了我自己的东西,我设置了$error=null,然后将error设置为一个数字,这个数字后来会变成一条消息 问题 这种方法有什么缺点吗?我是不是更喜欢尝试/抓住还是别的什么?如果可能的话,我想保持代码简短整洁 在这个简短的代码示例中,错误处理似乎是类的重要组成部分。在我的实际代码中,只有几百行,它不是整个代码的一大部分 我问这个

我正在进行一个项目,我不想直接向用户抛出错误。相反,我想要定制的错误消息accur

以后我还需要保留一个错误号,以便自定义来自类外部的错误消息,如错误消息数组

所以我做了我自己的东西,我设置了
$error=null
,然后将error设置为一个数字,这个数字后来会变成一条消息

问题 这种方法有什么缺点吗?我是不是更喜欢尝试/抓住还是别的什么?如果可能的话,我想保持代码简短整洁

在这个简短的代码示例中,错误处理似乎是类的重要组成部分。在我的实际代码中,只有几百行,它不是整个代码的一大部分

我问这个问题的原因是,我有一种感觉,在这种情况下,我可能会重新发明轮子。是吗


如果有更好的解决方案,我会很高兴看到代码的样子。

我可能会将业务逻辑与错误处理分开,以进一步简化每个部分。通过使用异常,您可以简化业务逻辑;每当遇到不允许的情况时,您只需
抛出一个异常,从而防止进入任何不一致的状态。业务逻辑类不必关心如何进一步处理此错误,它只需要提出错误。然后,您应该围绕业务逻辑类创建一个单独的包装器,该包装器只关心处理任何错误,并将它们格式化为数组或其他类型的响应,这些响应将在别处处理。大致如下:

class ProjectException extends Exception {
    public function __construct($num) {
        parent::__construct(get_called_class() . ": $num");
    }
}

class NestedLevelOneException extends ProjectException {
    // customise __construct here if desired
}

class NestedLevelTwoException extends ProjectException {}

class Project {
    public function callMeFirst($num) {
        $this->nestedLevelOne($num);
        $this->nestedLevelTwo($num);
    }

    public function callMeSecond($num) {
        $this->nestedLevelTwo($num);
    }

    protected function nestedLevelOne($num) {
        if ($num !== 1) {
            throw new NestedLevelOneException($num);
        }

        // do stuff
    }

    protected function nestedLevelTwo($num) {
        if ($num !== 20) {
            throw new NestedLevelTwoException($num);
        }

        // do stuff
    }
}

class ProjectService {
    protected $project;

    public function __construct(Project $project = null) {
        $this->project = $project ?: new Project;
    }

    public function process($a, $b) {
        try {
            $this->project->callMeFirst($a);
            $this->project->callMeSecond($b);
            return ['success' => true];
        } catch (ProjectException $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}

$api = new ProjectService;
print_r($api->process(1, 2));
  • 通过定义三个独立的异常,您可以灵活地处理错误的方式和位置。您可以专门捕获
    NestedLevel*异常
    ,或者使用
    ProjectException
    捕获其中任何一个异常

  • 通过让方法抛出异常,您可以获得灵活的错误处理可能性。您可以自由地不捕获异常并终止程序,如果您的一个业务需求没有得到满足,这是完全合理的。或者,您可以在准备处理该错误的级别捕获异常,并将其转化为可以执行的有意义的操作

  • 通过将错误消息的生成移动到异常中,可以保持错误类型及其消息的自包含性。只有一个地方可以定义可能发生的错误类型及其错误消息的外观;而不是将其分散到整个代码库中。您仍然可以在UI中自由选择其他错误消息,例如,将不同类型的错误本地化为多种语言;只需检查异常对象的类型

  • 通过使用一个独立的
    ProjectService
    ,它关心如何处理这些异常并将其转换为数组响应,可以缩小每个类的范围,使每个类更加灵活和简单


  • 为什么不使用异常…?通过指定您自己的异常类,您可以通过编程简单地区分错误类型,并且它们也包含自己的消息。是的,谢谢!我现在在代码中看到的好处是1。我自己不需要管这些冒泡的事。我可以晚一点赶上。2.我有点惊讶,但实际上我可以减少代码,主要是因为1。
    Array
    (
      [success] => 
      [error] => Array
        (
          [id] => 2
            [message] => Another error at level two: 2
        )
    )
    
    class ProjectException extends Exception {
        public function __construct($num) {
            parent::__construct(get_called_class() . ": $num");
        }
    }
    
    class NestedLevelOneException extends ProjectException {
        // customise __construct here if desired
    }
    
    class NestedLevelTwoException extends ProjectException {}
    
    class Project {
        public function callMeFirst($num) {
            $this->nestedLevelOne($num);
            $this->nestedLevelTwo($num);
        }
    
        public function callMeSecond($num) {
            $this->nestedLevelTwo($num);
        }
    
        protected function nestedLevelOne($num) {
            if ($num !== 1) {
                throw new NestedLevelOneException($num);
            }
    
            // do stuff
        }
    
        protected function nestedLevelTwo($num) {
            if ($num !== 20) {
                throw new NestedLevelTwoException($num);
            }
    
            // do stuff
        }
    }
    
    class ProjectService {
        protected $project;
    
        public function __construct(Project $project = null) {
            $this->project = $project ?: new Project;
        }
    
        public function process($a, $b) {
            try {
                $this->project->callMeFirst($a);
                $this->project->callMeSecond($b);
                return ['success' => true];
            } catch (ProjectException $e) {
                return ['success' => false, 'error' => $e->getMessage()];
            }
        }
    }
    
    $api = new ProjectService;
    print_r($api->process(1, 2));