【问题标题】:Using try/catch via php as substitute for nested if/else通过 php 使用 try/catch 代替嵌套的 if/else
【发布时间】:2023-03-24 15:33:01
【问题描述】:

我已经看到一些关于这个主题的问题,但我认为除了最基本的示例之外,我更根本地缺乏如何最好地使用 try/catch 块。

在这个特定的案例中,我有一系列技术来解决一个问题,从简单到相当复杂,我的想法是这样的:

if ($zombie_killer -> board_with_nail == 'failed') {
    if ($zombie_killer -> machette == 'failed') {
       if ($zombie_killer -> shotgun == 'failed') {
           $this -> panic;
       }
    }
}

但是,相反,我认为使用 try/catch 块可能是更好的方法,以便有更多空间添加自定义子流程,例如记录该技术为何不起作用,更新 UI反映“比平时更长的保持时间”,或其他什么。所以我想它会是这样的:

try {
    $zombie_killer -> board_with_nail;
}
catch(Exception $e) {
    try {
        $zombie_killer -> machette;
    }
}

但这感觉并没有好多少,考虑到其他人对“if/else vs try/catch”的所有反响,我很清楚,至少存在很大的差异和原因使用它们。这就是为什么我要询问这个用例的原因,因为我觉得最好通过 try/catch 来处理它,但不知道它是否感觉不对,因为我没有真正使用它们或者因为我没有正确地接近这个。

【问题讨论】:

  • 有什么理由不使用if(($zombie_killer -> board_with_nail == 'failed') && ($zombie_killer -> machette == 'failed') && ($zombie_killer -> shotgun == 'failed'))

标签: php exception-handling conditional


【解决方案1】:

作为个人观点,我认为,与 if/else 不同,try/catch 用于处理异常,而不是用例,因此它们更好地用于此目的,而不是用于处理您想做的事情,具体取决于一种情况。

【讨论】:

    【解决方案2】:

    异常不是表示条件语句的替代方法。例外是在特殊情况下,比如试图用枕头杀死僵尸:

    function kill_zombie($weapon) {
        if (!$weapon instanceof FireArm && !$weapon instanceof HeavyObject)
            throw new Exception("Zombies can only be killed with firearms and heavy objects");
        // ...
    }
    

    【讨论】:

    • 好的,这是有道理的,尤其是在将其绑定到 elxordi 的 readDatabase 多捕获示例时,它没有嵌套尝试,它考虑了一种方法可能抛出的各种异常。但是使用链式if(!$zombie_killer-> board && !$zombie_killer -> machette) 可能会更紧,我试图让选项保持宽松,因为在我看来更重要的是个别技术有效(或以其他方式可以处理)并且我有一个方法是一次性“建议使用”组合,但保持细节公开或至少受到保护,以便..
    • ...可以尝试其他组合或一次性尝试。也许我错误地将异常抛出作为打开方法以“订阅就绪”或“松散”的解决方案,因为我希望那些实现库的人也能够根据任何给定的结果触发子例程。因此,如果$zombie_killer -> shotgun 失败,他们可以重新加载并重试,或者向用户输出消息,或者动画,或者提供退出选项。基本上我喜欢这样的想法,即它是一系列看起来有状态的“尝试”或“尝试”,而不是看起来无状态的条件。还是我很奇怪?
    • 刚刚改进了我的答案。顺便说一句,请选择一个最终的正确答案。
    【解决方案3】:

    try/catch 的理念与您描述的不同。使用它的好方法是根据发生的错误捕获不同的异常。例如:

    try {
        $value = readDatabase();
        writeDatabase($++value);
    } catch (ReadErrorException $e) {
        // do something
    } catch (WriteErrorException $e) {
        // do something
    }
    

    如果您想实现您正在寻找的东西,您可以像使用 and 一样简单,如果您不需要更多代码。如果你这样做,只需使用 elseif。

    例如,您的代码可能变成:

    if (
        $zombie_killer -> board_with_nail == 'failed'
        && $zombie_killer -> machette == 'failed'
        && $zombie_killer -> shotgun == 'failed'
    ) {
        $this -> panic;
    }
    

    另外,好的方法是使用布尔值作为属性:

    if (
        !$zombie_killer -> board_with_nail
        && !$zombie_killer -> machette
        && !$zombie_killer -> shotgun
    ) {
        $this -> panic;
    }
    

    编辑:在阅读您的 cmets 其他答案后

    根据您所说的,我向您建议一个替代解决方案。了解 $zombie_killer 是一个类,您可以创建一个名为的公共方法,例如 kill()。该方法可以访问类的public、private和protected属性。

    我会先写一个没有例外的例子。

    类内:

    public function kill()
    {
        if ($zombie_killer -> board_with_nail != 'failed') return true;
        if ($zombie_killer -> machette != 'failed') return true;
        if ($zombie_killer -> shotgun != 'failed') return true;
    
        return false;
    }
    

    在另一个文件中,我们正在讨论的那个:

    if (!$zombie_killer->kill()) {
       $this->panic;
    }
    

    如您所见,代码更简洁,函数的默认行为是假设僵尸不会被杀死,例外情况是如果用于杀死僵尸的方法之一成功。这与我们通常的想法相反:我们假设我们可以杀死僵尸,而例外情况是如果一切都失败了。但这只是一个哲学问题,您可以将代码颠倒过来,它仍然可以工作。

    让我们看看例外情况。

    类文件:

    public function kill()
    {
        if (
            $zombie_killer -> board_with_nail == 'failed' 
            && $zombie_killer -> machette == 'failed'
            && $zombie_killer -> shotgun == 'failed'
        ) {
            throw new NotKilledException();
        }
    }
    

    其他文件:

    try {
        $zombie_killer->kill();
    } catch (Exception $e) {
        $this->panic;
    }
    

    所以,你看到了吗?在这种情况下,异常版本没有多大帮助,因为您仍然必须执行嵌套 if,因为条件必须完成三种不同类型的 kill failed。例外是不杀死僵尸。因为您希望执行异常代码 $this->panic。

    现在,您必须选择更适合您的实施方式。两者都是正确的,开发人员都会看到它是正确的。不过我会选择第一个,因为通过简单的复制粘贴,您可以为您的zombie_killer 添加更多杀戮类型,而且阅读起来更干净。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-26
      相关资源
      最近更新 更多