PHP是否具有短路评估?


72

给出以下代码:

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

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


结合所有这些答案进行一些阅读:en.wikipedia.org/wiki/Short-circuit_evaluation
Aaron W.

1
这是指短路评估的主题,不同的语言对短路评估的处理方式不同。
AJ。

1
@AJ:老实说,我还没有看到一种(严重/广泛使用的)编程语言,它没有对逻辑和逻辑或进行短路评估。你有例子吗?

1
@delnan-我想你的意思是“大多数广泛使用的编程语言没有实现任何热切的运算符。”
AJ。

3
@delnan-想到VB和Fortran ...
AJ。

Answers:


99

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

如果要验证,请尝试以下操作:

function saySomething()
{
    echo 'hi!';
    return true;
}

if (false && saySomething())
{
    echo 'statement evaluated to true';
}

22
短路评估!=懒惰。

1
@delnan:这是一个惰性评估的示例。请参阅books.google.com/…
Zach Rattner

1
一个很小的例子,一个可以争论的例子(同样,如果说if语句是懒惰评估的例子)。惰性求值更为笼统-它适用于所有地方的每个表达式(尽管您通常可以不使用该值而强制求值)。那本书的摘录是正确的。

您知道禁用此行为的任何方法吗?
Radu Murzea

5
@RaduMurzea:短路并不是我期望的事情,因为它可能会对整个程序和导入的库产生不利影响。考虑一下在读取变量之前检查是否已设置变量的情况if (isset($var['index']) && $var['index'] === "something")。如果需要在布尔表达式中求值每个条件,则在if语句之前求值并保存它们,然后在if条件中检查结果。
贾斯汀C

10

是的,它确实。这是一个依靠短路评估的小技巧。有时,您可能会有一个小的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()


7

按位运算符&|。他们总是对两个操作数求值。

逻辑运算符ANDOR&&,和||

  • 所有四个运算符仅在需要时评估右侧。
  • AND并且OR具有比&&和低的优先级||。请参见下面的示例。

 

从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


7
“ AND和OR始终对两个操作数求值。” - 这不是真的。它们的优先级仅比&&和低,||但除此之外,它们的语义与&&和相同||
axiac

4

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

我运行了此测试:

$one = true;

$two = 'Cabbage';

$test = $one && $two;

echo $test;

和PHP 7.0.8返回1,不是Cabbage


1
我认为&&导致php将所有内容转换为布尔值,因此将$two其转换为true,然后回显为1。您将需要对其true||(echo 'no short circuit')进行测试(或类似的测试)。
Teepeemm '19

3

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


1

我已经创建了自己的短路评估逻辑,不幸的是,它与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;

您可以跳过在问号之后再次编写true条件变量的步骤,例如:

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

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

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

1
这种逻辑与?:JavaScript / Perl的逻辑一样||
trysis

trysys不太完全-似乎会扫描左手参数以查找是否为true的表达式-无论其周围的函数如何。(例如:isset($ var)?:如果第一个表达式为true,则'1'会生成$ var)。
杰拉德·奥尼尔

-5

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

function saySomething()
{
    print ('hi!');
    return true;
}

if (1 || saySomething())
{
    print('statement evaluated to true');
}

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

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

此外,这不仅是性能问题,如果您在比较中进行分配,或者进行了有意义的改变,而不仅仅是比较内容,那么结果可能会不同。

无论如何...要小心。


这可能是有关短路评估还是急切的原因。一旦知道结果为假,它将停止。
Grantwparks 2012年

8
实际上,我只是运行您的代码,而没有执行saySomething()。PHP 5.3.13
grantwparks 2012年

3
+1 grantwparks,saySomething()并没有得到执行。PHP正确短路。我使用PHP编写此类代码已有十年之久了,我不记得曾经挂过这个问题。如果我觉得有些额外的澄清很重要,有时我会编写更多详细的代码,但是通常,代码注释足以涵盖该问题。
杰森

4
你是对的。我再次运行自己的测试,并且函数saySomething()从未执行。我不知道在第一次测试中可能出了什么问题。抱歉:(
Beto Aveiga

1
它证明了PHP行为是一致的。如果OR条件中的第一个值是true,则显而易见,如果为true,则不处理其余语句,其与短路行为一致。
法拉兹

-5

旁注:如果要避免延迟检查并运行条件的每个部分,在这种情况下,您需要使用逻辑AND,如下所示:

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

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


3
这不是“逻辑与”,而是按位运算符。这可能会让您感到惊讶,因为它的工作原理与逻辑完全相同&&
deceze

1
这是逻辑与门,为什么你说不是?是的,正如我所说的不是&&或AND。这不会令我感到惊讶,因为我实际上知道它是如何工作的。就像检查此表并使用正确的返回类型一样简单:1&1 = 1 1&0 = 0 0&1 = 0 0&0 = 0
Patricio Rossi

2
PHP中的逻辑按位与之间有区别;这不是逻辑与。即使知道它的规则是什么,未来的读者也可能不会。
deceze

1
这不是OP要求的逻辑操作。使用单个&是按位运算。
GraSim

1
您谈论的是运算符,而我谈论的是门,在PHP中,两个运算符都是AND门,但其中之一是短路的。
Patricio Rossi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.