通过php使用try/catch替代嵌套的if/else

通过php使用try/catch替代嵌套的if/else,php,exception-handling,conditional,Php,Exception Handling,Conditional,我已经看到了围绕这个主题讨论的一些问题,但我认为除了最基本的示例之外,我还缺少如何最好地使用try/catch块的更基本的问题 在这个特定的案例中,我有一系列的技术来解决一个问题,从简单到相当复杂,我想到的是: if ($zombie_killer -> board_with_nail == 'failed') { if ($zombie_killer -> machette == 'failed') { if ($zombie_killer -> sho

我已经看到了围绕这个主题讨论的一些问题,但我认为除了最基本的示例之外,我还缺少如何最好地使用try/catch块的更基本的问题

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

if ($zombie_killer -> board_with_nail == 'failed') {
    if ($zombie_killer -> machette == 'failed') {
       if ($zombie_killer -> shotgun == 'failed') {
           $this -> panic;
       }
    }
}
try {
    $zombie_killer -> board_with_nail;
}
catch(Exception $e) {
    try {
        $zombie_killer -> machette;
    }
}
但是相反,我认为使用try/catch块可能是一种更好的方法,这样就有更多的空间添加自定义子进程,比如记录技术不起作用的原因,更新UI以反映“比平常更长的保持时间”,等等。所以我想应该是这样的:

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

但这感觉并没有太好,考虑到其他人在“如果/否则比尝试/抓住更好”中得到的所有回击,我很清楚,至少,使用它们有很大的不同和理由。这就是为什么我要问这个用例,因为我觉得用try/catch来处理它是最好的,但是我不知道是因为我没有太多地使用它们,还是因为我没有正确地处理它。

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

try {
    $value = readDatabase();
    writeDatabase($++value);
} catch (ReadErrorException $e) {
    // do something
} catch (WriteErrorException $e) {
    // do something
}
如果你想实现你想要的,你可以简单地使用和,如果你不需要更多的代码。如果你这样做了,就用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;
}
编辑:阅读您对其他答案的评论后

根据你所说的,我向你提出另一个解决办法。理解$zombie\u killer是一个类,您可以创建一个名为kill()的公共方法。此方法可以访问类的公共、私有和受保护属性

我将首先写一个没有例外的例子

课堂内:

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,因为条件必须完成三种不同类型的终止失败。例外是不要杀死僵尸。因为您希望执行异常代码$this->panic


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

从个人角度来看,我认为,与if/else不同,try/catch是用来处理异常的,而不是用例,因此它们更适合用于处理异常,不用于根据情况处理您想要做的事情。

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

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

如果($zombie_killer->board_with_nail='failed')&($zombie_killer->machette='failed')&($zombie_killer->shotgunt='failed'),有什么理由不使用
?好吧,这是有意义的,特别是当将它绑定到elxordi的
readDatabase
多捕获示例时,它没有嵌套尝试,它考虑了一个方法可能抛出的各种异常。但是如果(!$zombie\u killer->board&!$zombie\u killer->machette)
使用链式
可能会更紧一些,我会尽量让选项保持宽松,因为在我看来,更重要的是,单个技术可以工作(或者可以处理),而且我有一个一次性“建议使用”组合的方法,但要将细节公开或至少加以保护,以便……可以尝试其他组合或一次性尝试。也许我把异常抛出误认为是将方法开放为“订阅就绪”或“松散”的解决方案,因为我希望那些实现库的人也能够基于任何给定的结果启动子例程。因此,如果
$zombie\u killer->shotgun
失败,他们可以重新加载并重试,或者向用户输出消息或动画,或者给出退出选项。基本上,我喜欢这样的想法,即它是一系列看起来有状态的“尝试”或“尝试”,而不是看起来无状态的条件。或者我只是有点奇怪?只是改进了我的答案。顺便说一句,请选择最后的正确答案。