【问题标题】:Does PHP have short-circuit evaluation?PHP有短路评估吗?
【发布时间】:2011-08-07 08:59:06
【问题描述】:

给定以下代码:

if (is_valid($string) && up_to_length($string) && file_exists($file)) 
{
    ......
}

如果is_valid($string) 返回false,php 解释器是否仍会检查后面的条件,例如up_to_length($string)
如果是这样,那为什么它不需要做额外的工作呢?

【问题讨论】:

  • 这里指的是短路求值的话题,不同的语言处理不同。
  • @AJ:老实说,我还没有看到一种(严重/广泛使用的)编程语言没有逻辑和逻辑或的短路评估。你有例子吗?
  • @delnan - 我认为您的意思是“最广泛使用的编程语言没有实现任何 eager 运算符。”
  • @delnan - 想到 VB 和 Fortran...

标签: php if-statement short-circuiting


【解决方案1】:

不,如果第一个条件不满足,它不再检查其他条件。

【讨论】:

    【解决方案2】:

    是的,PHP 解释器是“惰性”的,这意味着它将进行尽可能少的比较来评估条件。

    如果你想验证,试试这个:

    function saySomething()
    {
        echo 'hi!';
        return true;
    }
    
    if (false && saySomething())
    {
        echo 'statement evaluated to true';
    }
    

    【讨论】:

    • 短路评估!= 懒惰。
    • @delnan:这是一个惰性求值的例子。见books.google.com/…
    • 一个 tiny 示例,一个有争议的示例(同样,可以将 if 语句称为惰性求值示例)。惰性求值更为通用 - 它适用于 every 表达式 everywhere (尽管您通常可以在不使用值的情况下强制求值)。那本书的摘录是正确的。
    • 你知道有什么方法可以禁用这种行为吗?
    • @RaduMurzea:短路不是我希望切换的东西,因为它会对整个程序和导入的库产生不利影响。考虑在读取变量if (isset($var['index']) && $var['index'] === "something") 之前检查变量是否已设置的情况。如果需要对布尔表达式中的每个条件进行求值,则在 if 语句之前求值并保存,然后在 if 条件中检查结果。
    【解决方案3】:

    我的选择:相信 PHP 中的短路评估...

    function saySomething()
    {
        print ('hi!');
        return true;
    }
    
    if (1 || saySomething())
    {
        print('statement evaluated to true');
    }
    

    条件中的第二部分1 || saySomething() 无关紧要,因为这将始终返回 true。不幸的是 saySomething() 被评估和执行。

    也许我误解了短路表达式的确切逻辑,但这看起来不像 “它将进行尽可能少的比较”

    此外,这不仅仅是性能问题,如果您在比较中进行分配,或者如果您做了一些有所作为的事情,而不仅仅是比较东西,您可能会得到不同的结果。

    无论如何...小心点。

    【讨论】:

    • 这可能是短路评估或急切的原因。一旦知道结果将是错误的,它就会停止。
    • 其实我只是运行了你的代码,并没有执行saySomething()。 PHP 5.3.13
    • +1 到 grantwparks,saySomething() 确实 not 被执行。 PHP 正确短路。十年来,我一直在用 PHP 编写这种代码,我不记得曾经挂断过这个问题。有时,如果我觉得更清楚一点很重要,我会编写更冗长的代码,但通常代码注释足以涵盖该问题。
    • 你是对的。我再次运行了自己的测试,并且函数 saySomething() 永远不会被执行。我不知道在我的第一次测试中可能出了什么问题。对不起:(
    • 它证明了 php 行为是一致的。如果 OR 条件中的第一个值为真,则很明显,如果为真,则它不会处理与短路行为一致的其余语句。
    【解决方案4】:

    旁注:如果您想避免惰性检查并运行条件的每个部分,在这种情况下,您需要像这样使用逻辑 AND:

    if (condition1 & condition2) {
     echo "both true";
    }
    else {
     echo "one or both false";
    }
    

    这在您需要调用两个函数时很有用,即使第一个函数返回 false。

    【讨论】:

    • 这不是“逻辑与”,而是位运算符。它可能会让您感到惊讶,因为它确实工作完全像逻辑&&
    • 是逻辑与门,为什么说不是?是的,正如我所说的不是 && 或 AND。这不会让我感到惊讶,因为我实际上知道它是如何工作的。就像检查这个表并使用正确的返回类型一样简单:1 & 1 = 1 1 & 0 = 0 0 & 1 = 0 0 & 0 = 0
    • PHP 中的 logicalbitwise AND 是有区别的;这里 不是 逻辑与。即使知道它的规则是什么,未来的读者也可能不知道。
    • 这不是 OP 要求的逻辑操作。使用单个 & 是按位运算。
    • 你说的是操作符,我说的是门,在 PHP 中,两个操作符都是 AND 门,但一个是短路的。
    【解决方案5】:

    我已经创建了自己的短路评估逻辑,不幸的是它不像 javascripts 快速语法,但也许这是一个你可能会发现有用的解决方案:

    $short_circuit_isset = function($var, $default_value = NULL) {
        return  (isset($var)) ? : $default_value;
    };
    
    $return_title = $short_circuit_isset( $_GET['returntitle'], 'God');
    
    // Should return type 'String' value 'God', if get param is not set
    

    我不记得我从哪里得到以下逻辑,但如果你执行以下操作;

    (isset($var)) ? : $default_value;
    

    您可以跳过必须在问号之后再次写入真正的条件变量,例如:

    (isset($super_long_var_name)) ? $super_long_var_name : $default_value;
    

    作为非常重要的观察,当以这种方式使用 三元运算符 时,您会注意到,如果进行比较,它只会传递该比较的值,因为不只是一个变量。例如:

    $num = 1;
    $num2 = 2;
    var_dump( ($num < $num2) ? : 'oh snap' );
    // outputs bool 'true'
    

    【讨论】:

    • ?: 的逻辑与 JavaScript/Perl 的 || 类似。
    • 不完全是 trysys - 左侧参数似乎被扫描以查找如果为真则返回的表达式 - 无论它周围的函数如何。 (例如: isset($var) ?: '1' 如果第一个表达式为真,则产生 $var)。
    【解决方案6】:

    Bitwise operators&amp;|。 他们总是评估两个操作数。

    Logical operatorsANDOR&amp;&amp;||

    • 所有四个运算符仅在需要时评估右侧。
    • ANDOR 的优先级低于 &amp;&amp;||。请参见下面的示例。

     

    来自 PHP 手册:

    // The result of the expression (false || true) is assigned to $e
    // Acts like: ($e = (false || true))
    $e = false || true;
    
    // The constant false is assigned to $f before the "or" operation occurs
    // Acts like: (($f = false) or true)
    $f = false or true;
    

    在本例中,e 将是 truef 将是 false

    【讨论】:

    • “AND 和 OR 总是计算两个操作数。” -- 这不是真的。它们的优先级仅低于&amp;&amp;||,但除此之外它们具有与&amp;&amp;|| 相同的语义。
    • 将在手册中添加很好的提示:“请注意,PHP 的布尔运算符 always 返回一个布尔值...与其他返回最后一个评估表达式的值的语言相反。”
    【解决方案7】:

    是的,确实如此。这是一个依赖短路评估的小技巧。有时你可能有一个小的 if 语句,你更愿意将它写成三元组,例如:

        if ($confirmed) {
            $answer = 'Yes';
        } else {
            $answer = 'No';
        }
    

    可以改写为:

       $answer = $confirmed ? 'Yes' : 'No';
    

    但是如果 yes 块也需要运行一些函数呢?

        if ($confirmed) {
            do_something();
    
            $answer = 'Yes';
        } else {
            $answer = 'No';
        }
    

    好吧,由于短路评估,仍然可以重写为三进制:

        $answer = $confirmed && (do_something() || true) ? 'Yes' : 'No';
    

    在这种情况下,表达式 (do_something() || true) 不会改变三元的整体结果,但会确保三元条件保持 true,而忽略 do_something() 的返回值。

    【讨论】:

      【解决方案8】:

      根据我现在的研究,PHP 似乎没有与 JavaScript 相同的 &amp;&amp; 短路运算符。

      我运行了这个测试:

      $one = true;
      
      $two = 'Cabbage';
      
      $test = $one && $two;
      
      echo $test;
      

      PHP 7.0.8 返回1,而不是Cabbage

      【讨论】:

      • 我认为&amp;&amp; 导致php 将所有内容转换为布尔值,因此$two 被转换为true,然后回显为1。你需要true||(echo 'no short circuit') 来测试它(或类似的东西)。
      猜你喜欢
      • 2017-01-21
      • 2012-05-17
      • 1970-01-01
      • 2015-11-14
      • 2012-02-10
      • 2010-12-21
      • 1970-01-01
      相关资源
      最近更新 更多