构建条件逻辑的最佳方法是什么?

发布于 2024-09-10 09:49:32 字数 2098 浏览 2 评论 0原文

我发现有许多不同的方法来构建条件逻辑。据我所知,只要我们设置错误来结束脚本(或者您可以想象相同的示例,但在函数中带有返回),那么以下示例是相同的:

示例 1

if($condition1) {
    trigger_error("The script is now terminated");
    }

if($condition2) {
    trigger_error("The script is now terminated");
    }

echo "If either condition was true, we won't see this printed";

示例 2

if(!$condition1) {
    if(!$condition2) {
        echo "If either condition was true, we won't see this printed";
        }
    else {
        trigger_error("The script is now terminated");
        }
    }
else {
    trigger_error("The script is now terminated");
    }

示例 3

if($condition1) {
    trigger_error("The script is now terminated");
    }
else {
    if($condition2) {
        trigger_error("The script is now terminated");
        }
    else {
        echo "If either condition was true, we won't see this printed";
        }
    }

示例 4 -- 改编自 Fraser 的回答

function test($condition) { 
    if($condition) {
        trigger_error("The script is now terminated");
        }   
    }

test($condition1);

test($condition2);

echo "If either condition was true, we won't see this printed";

就个人而言,我倾向于像示例 1 那样编写代码。这是因为我觉得通过检查条件以这种方式结束脚本(或函数),我可以清楚地定义脚本执行的内容和未执行的内容,即条件执行之前的所有内容以及该行之后的所有内容尚未执行。这意味着当我在第 147 行遇到错误时,我立即知道发生了什么,帮助我更快地找到错误。此外,如果我突然意识到我需要在 $condition1 之前测试 $condition2,我可以通过简单的复制粘贴进行更改。

我看到很多代码都是像示例 2 中那样编写的,但对我来说,这似乎调试起来要复杂得多。这是因为,当嵌套变得太大时,错误将在底部的某个较远的行处触发,并与由大量嵌套代码引起的条件分开。此外,改变条件序列可能会变得更加混乱。

您可以混合这两种样式,例如示例 3,但这似乎会使问题变得过于复杂,因为所有“其他”本质上都是多余的。

我错过了什么吗?构造条件代码的最佳方法是什么?还有比这些例子更好的方法吗? 在某些特定情况下,一种风格可能优于另一种风格?

编辑:示例 4 看起来很有趣,但我没有考虑过。您还可以传入错误消息作为第二个参数。

谢谢!

PS 请记住,我可能需要在检查 $condition1 和 $condition2 之间执行一些任意步骤,因此任何替代方案都必须适应这一点。否则,还有更好的选择,例如 if($condition1 || $condition2)。

It occurs to me that there are number of different ways to structure conditional logic. As far as I can see, as long as we set errors to end the script (or you can imagine the same examples but with a return in a function), then the following examples are equal:

Example 1

if($condition1) {
    trigger_error("The script is now terminated");
    }

if($condition2) {
    trigger_error("The script is now terminated");
    }

echo "If either condition was true, we won't see this printed";

Example 2

if(!$condition1) {
    if(!$condition2) {
        echo "If either condition was true, we won't see this printed";
        }
    else {
        trigger_error("The script is now terminated");
        }
    }
else {
    trigger_error("The script is now terminated");
    }

Example 3

if($condition1) {
    trigger_error("The script is now terminated");
    }
else {
    if($condition2) {
        trigger_error("The script is now terminated");
        }
    else {
        echo "If either condition was true, we won't see this printed";
        }
    }

Example 4 -- Adapted from Fraser's Answer

function test($condition) { 
    if($condition) {
        trigger_error("The script is now terminated");
        }   
    }

test($condition1);

test($condition2);

echo "If either condition was true, we won't see this printed";

Personally, I lean towards writing code as in Example 1. This is because I feel that by checking for conditions that end the script (or function) in this way, I can clearly define what the script executed and not executed i.e. everything before the condition has been executed and everything after the line has not. This means when I get an error on line 147, I know immediately what has happened helping me to find a bug faster. Furthermore, if I suddenly realise I need to test $condition2 before $condition1, I can make a change by a simple copy paste.

I see a lot of code written like in Example 2 but for me, this seems much more complex to debug. This is because, when the nesting gets too great, an error will get fired off at some distant line at the bottom and be separated from the condition that caused it by a huge chunk of nested code. Additionally, altering the conditional sequence can be a lot messier.

You could hybrid the two styles, such as in Example 3, but this then seems to overcomplicate matters because all of the 'else's are essentially redundant.

Am I missing something? What is the best way to structure my conditional code? Is there a better way than these examples? Are there specific situations under which one style may be superior to another?

Edit: Example 4 looks quite interesting and is not something I had considered. You could also pass in an error message as a second parameter.

Thanks!

P.S. Please keep in mind that I might need to do some arbitrary steps inbetween checking $condition1 and $condition2 so any alternatives must accommodate that. Otherwise, there are trivially better alternatives such as if($condition1 || $condition2).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

合久必婚 2024-09-17 09:49:32

我属于示例1阵营。根据经验,所需的缩进越少越好。

// Exit early if there are errors.
if ($n < 0) {
    die "bad n: $n";
}

// Handle trivial cases without fuss.
if ($n == 0) {
    return 0;
}

/* Now the meat of the function. */
$widget->frob($n);
foreach ($widget->blaxes as $blax) {
    checkFrobbingStatus($blax);
}
// ...And another 20 lines of code.

当您使用 if/else 并将成功代码和错误代码放在并行部分中时,您会使两个代码块看起来相等。实际上,应该不再强调边缘情况和错误条件。通过有意尽早处理错误,然后将“重要”代码放入 else 子句中,我觉得这样可以在视觉上更清晰地显示重要代码的位置。

“这是所有的先决条件。现在这是好东西。”

I am in the Example 1 camp. As a rule of thumb, the less indentation needed, the better.

// Exit early if there are errors.
if ($n < 0) {
    die "bad n: $n";
}

// Handle trivial cases without fuss.
if ($n == 0) {
    return 0;
}

/* Now the meat of the function. */
$widget->frob($n);
foreach ($widget->blaxes as $blax) {
    checkFrobbingStatus($blax);
}
// ...And another 20 lines of code.

When you use an if/else and put the success and error code in parallel sections you make it appear as if the two code blocks are equal. In reality, the edge cases and error conditions should be de-emphasized. By intentionally handling errors early and then not putting the "important" code in an else clause I feel like that makes it visually clearer where the important code is.

"Here are all the preconditions. And now here's the good stuff."

能否归途做我良人 2024-09-17 09:49:32

就我个人而言,我讨厌嵌套的 if-else 语句,所以从你的例子中对我来说#1。我会考虑的另一个选项如下所示。

function test($condition) { 
  if($condition) {
    trigger_error("The script is now terminated");
  }   
}

test($condition1);

//do stuff...

test($condition2);

//passed the tests

编辑:我越想越觉得函数式方法是迄今为止最好的方法,因为它不需要编写多次测试条件的逻辑。它还具有更高的可读性,因为很明显您正在“测试”条件(只要您为函数指定一个有意义的名称)。此外,正如问题编辑中所指出的,将其他参数传递给函数也很简单。 IE

function test($c, $msg) { 
  if($c) {
    trigger_error($msg);
  }   
}

test($condition1, "condition1 error");
test($condition2, "condition2 error");

Personally I hate nested if-else statements so #1 for me from your examples. The other option I would look at is something like the following.

function test($condition) { 
  if($condition) {
    trigger_error("The script is now terminated");
  }   
}

test($condition1);

//do stuff...

test($condition2);

//passed the tests

EDIT: The more I think about it a functional approach is by far the best way in that it negates having to write the logic that tests the conditions more than once. It also allows greater readability because it is obvious you are 'testing' the condition (as long as you give the function a meaningful name). Also, as pointed out in the question edit it would be trivial to pass other parameters to the function. i.e.

function test($c, $msg) { 
  if($c) {
    trigger_error($msg);
  }   
}

test($condition1, "condition1 error");
test($condition2, "condition2 error");
初心未许 2024-09-17 09:49:32

#1 是迄今为止最清晰的。但是,如果以某种方式将之前结束执行的事情更改为执行其他操作,那么它就会中断。

最好还是选择#1,但要确保用于“停止”的东西被明确命名以表明它确实停止事情,这样在10年内维护你的代码的人就不会'不要因为改变而意外地破坏它。

#1 is by far the clearest. However, if somehow the thing that previously ended the execution were changed to do something else, then it would break.

It's still probably best to go with #1, but make sure the thing being used to "stop" is clearly named to indicate that it does stop things, so that someone in 10 years maintaining your code doesn't accidentally break things by changing it.

隔岸观火 2024-09-17 09:49:32

我认为你的方法(示例1)在这种情况下是最有效的。但是,有时您不希望任何条件停止执行,而只想在 condition1 为 false 时执行 condition2。在这些情况下,elseelseif 效果很好。

I think your method (example 1) is the most efficient and effective in this type of situation. However, there are times when you do not want any conditions to halt execution and you only want to execute condition2 if condition1 is false. In these situations, an else or elseif works well.

一绘本一梦想 2024-09-17 09:49:32

我建议在任何可能出现错误的部分上使用“try”子句,并在每次发生错误时使用“抛出“错误描述””(如示例#1)。
这样,您就可以在程序中包含一次错误报告代码(在“catch”子句中),并且将代码拆分为函数将不会是重写错误处理的麻烦。

I suggest using ‘try‘ clause over any part that can have errors and use ‘throw "error description"‘ each time an error occures(like example #1).
That way you can have error reporting code once in your program (in the ‘catch‘ clause) and splitting code into functions won't be a hussle rewriting error handlig.

小瓶盖 2024-09-17 09:49:32

我更喜欢这种风格,如果任何一个条件块发生更改,这种风格都不会中断,因此它们不会退出执行。

if($condition1) {
    trigger_error("The script is now terminated");
}
if($condition2) {
    trigger_error("The script is now terminated");
}

if (!$condition1 && !$condition2) {
  echo "If either condition was true, we won't see this printed"; 
}

编辑:错过了 PS,因此更新了代码以匹配完整的问题详细信息。

I prefer this style, which doesn't break if either of the conditional blocks are changed so they do not exit execution.

if($condition1) {
    trigger_error("The script is now terminated");
}
if($condition2) {
    trigger_error("The script is now terminated");
}

if (!$condition1 && !$condition2) {
  echo "If either condition was true, we won't see this printed"; 
}

Edit: Missed the PS, so updated code to match the full question details.

唠甜嗑 2024-09-17 09:49:32

到目前为止,我总体上同意 Amber因为你的第一个选项似乎是最清晰的。这是我一直在与自己斗争的事情 - 到目前为止,我偶然发现的唯一推理如下:

  • 在阅读线性脚本时,第一种形式是最清晰的,因此非常适合简单的脚本
  • 当您需要确保整洁时,第二种形式是最干净的/ 清理操作

我提到第二个是因为这是一个棘手的问题。每个脚本可能是一个更大系统的一部分,事实上,您注入“bail out”代码的脚本元素可能会被多个地方调用。加入一些面向对象,你就会得到一个真正有潜力的泡菜。

我可以推荐的最佳经验法则是,如果您的脚本简单且线性,或者您正在进行快速原型设计,那么您需要使用第一种形式并在此时终止执行。任何更复杂或“企业式”的东西都将受益于(至少)模块化的重新设计,这样您就可以隔离方法和调用堆栈 - 以及可能的 OO 构建的封装。

随着当今一些更强大的调试和跟踪工具的出现,它变得更多的是个人风格而不是必要性的问题。您可能考虑的另一种选择是在每个救助区域之前(也可能之后)在注释中添加信息,以明确如果满足标准(或失败),替代方案是什么。

编辑:

我会说Fraser 的答案对于封装来说是最干净的。我唯一要补充的是,您可能会受益于将对象或哈希数组传递到标准“保释,我死了”方法,这样您就可以修改函数可用的信息,而无需始终更改参数列表(非常烦人...)。

也就是说,在生产系统中要小心,您可能需要在中间状态下清理资源。

I generally agree with Amber insofar as your first option seems the most legible. This is something I have fought with myself - thus far the only reasoning I have stumbled across is as follows:

  • The first form is clearest when reading through a linear script, so ideal for simple scripts
  • The second form is cleanest when you need to ensure tidy / clean-up operations

I mention the second because this is a sticky point. Each script may be part of a larger system, and in fact the script elements you are injecting the "bail out" code into may be called by multiple places. Throw in some OO and you've got a real potential pickle.

The best rule of thumb I can recommend is that if your scripts are simple and linear, or your are doing rapid prototyping, then you want to use the first form and just kill the execution at that point. Anything more complicated or "enterprise-esque" will benefit from (at least) a modular redesign so you can isolate the method and the call stack - and possibly encapsulation of an OO build.

With some of the more powerful debugging and tracing tools which are available these days, it is becoming more a matter of personal style than necessity. One other option you might consider is to put information in comments before (and possibly after) each bail-out zone which make it clear what the alternative is should the criteria be met (or failed).

Edit:

I'd say Fraser's answer is the cleanest for encapsulation. The only thing I would add it that you might benefit from passing an object or hash array into the standard "bail out, I'm dead" method so you can modify the information made available to the function without changing parameter lists all the time (very annoying...).

That said - be careful in production systems where you may need to clean up resources in an intermediate state.

昇り龍 2024-09-17 09:49:32

我也更喜欢#1。

此外,我真的很喜欢在条件语句中分配变量

,例如

if ( !$userName = $user->login() ) {
    die('could not log in');
}

echo "Welcome, $username";

我通常发现,在第一次编写代码时,我最终会得到一些混乱的嵌套条件语句,因此通常在第二遍期间我会返回并清理内容,尽可能多地取消嵌套条件语句。

除了看起来更整洁之外,我发现它在概念上更容易理解代码,您不必在心里跟踪分支逻辑。

对于无法删除且包含大量过程代码的分支逻辑,我通常最终将其放入函数/类方法中——理想情况下,这样我就可以在一个屏幕上看到正在发生的所有分支逻辑,但可以修改其中之一行动或逻辑不会破坏另一个。

I much prefer #1 as well.

In addition, I really like to assign variables during the conditionals

e.g.

if ( !$userName = $user->login() ) {
    die('could not log in');
}

echo "Welcome, $username";

I usually find that in the first write of code, I end up with a fair few messy nested conditional statements, so it's usually during a second pass that I go back and clean things up, un-nest as many of the conditionals that I can.

In addition to looking much neater, I find it conceptually much easier to understand code where you don't have to mentally keep track of branching logic.

For branching logic that can't be removed that contains lots of procedural code, I usually end up putting it in a function / class method -- ideally so I can see on one screen all the branching logic that is taking place, but modifying either the actions or the logic won't break the other one.

醉南桥 2024-09-17 09:49:32

实施例5

if($condition1 || $condition2)
{
    echo "If either condition was true, we won't see this printed";
}else
{
    trigger_error("The script is now terminated");
}

实施例6

function allAreTrue()
{
    foreach(func_get_args() as $check)
    {
       if(!$check)
       {
           return false;
       }
    }
    return true;
}

if(allAreTrue(true,true,$condition1,$condition2,false))
{
   exit("Invalid Arguments");
}

//Continue 

Example 5

if($condition1 || $condition2)
{
    echo "If either condition was true, we won't see this printed";
}else
{
    trigger_error("The script is now terminated");
}

Example 6

function allAreTrue()
{
    foreach(func_get_args() as $check)
    {
       if(!$check)
       {
           return false;
       }
    }
    return true;
}

if(allAreTrue(true,true,$condition1,$condition2,false))
{
   exit("Invalid Arguments");
}

//Continue 
明媚殇 2024-09-17 09:49:32

构造条件逻辑的最佳方法是遵循逻辑本身。

如果你有依赖关系,比如说,第一个条件的失败将使其他条件变得不必要是一回事。然后returngoto、嵌套条件和异常由您选择。

如果您要对测试做出决定,请说它

if (!isset($_GET['id'])) { 
  //listing part: 
} else { 
  // form displaying part: 
}  

elseelseifcase 领域。

等等
首先确定你的程序逻辑,然后编写它的逻辑。

并且 trigger_error() 与条件无关。这是调试功能,而不是与程序逻辑相关的功能。

The best way to structure conditional logic is to follow the logic itself.

If you have dependencies, say, failing of first condition will make others unnecessary is one thing. Then return, goto, nested conditions and exceptions at your choice.

If you are about to make decision upon a test, say

if (!isset($_GET['id'])) { 
  //listing part: 
} else { 
  // form displaying part: 
}  

it's else, elseif and case realm.

etc.
Determine your program logic first and write it's logic then.

and trigger_error() has nothing to do with conditions. It is debugging feature, not program logic related one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文