PHP有短路评估吗?

Posted

技术标签:

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

给定以下代码:

if (is_valid($string) && up_to_length($string) && file_exists($file)) 

    ......

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

【问题讨论】:

阅读所有这些答案:en.wikipedia.org/wiki/Short-circuit_evaluation 这里指的是短路求值的话题,不同的语言处理不同。 @AJ:老实说,我还没有看到一种(严重/广泛使用的)编程语言没有逻辑和逻辑或的短路评估。你有例子吗? @delnan - 我认为您的意思是“最广泛使用的编程语言没有实现任何 eager 运算符。” @delnan - 想到 VB 和 Fortran... 【参考方案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 operators 是 ANDOR&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') 来测试它(或类似的东西)。

以上是关于PHP有短路评估吗?的主要内容,如果未能解决你的问题,请参考以下文章

你能防止 Lua 中的短路评估吗?

使用 && 进行单线短路评估 ||在 JavaScript 中

C++如何处理&&? (短路评估)[重复]

短路逻辑评估运算符

如何防止短路评估?

C ++编译器优化和短路评估[重复]