85

Given the following code:

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

If is_valid($string) returns false, does the php interpreter still check later conditions, like up_to_length($string)?
If so, then why does it do extra work when it doesn't have to?

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
Muntasir
  • 1,130
  • 1
  • 8
  • 9
  • 1
    This is referring to the topic of short-circuit evaluation, and different languages handle it differently. – AJ. Apr 17 '11 at 16:31
  • 1
    @AJ: Honestly, I'm yet to see a (serious/widely used) programming language that doesn't have short-circuit evaluation for logical and and logical or. Do you have an example? –  Apr 17 '11 at 16:34
  • 1
    @delnan - I think what you meant was "Most widely-used programming languages don't implement any **eager** operators." – AJ. Apr 17 '11 at 16:37
  • @AJ: The operator `+` is perfectly eager in countless languages, and so is binary and/or. No, I'm sure I'm asking about languages where logical and and logical or don't short-circuit. –  Apr 17 '11 at 16:41
  • 4
    @delnan - VB and Fortran come to mind... – AJ. Apr 17 '11 at 16:47
  • Some reading to go along with all these answers: http://en.wikipedia.org/wiki/Short-circuit_evaluation – Aaron W. Apr 17 '11 at 16:30

8 Answers8

110

Yes, the PHP interpreter is "lazy", meaning it will do the minimum number of comparisons possible to evaluate conditions.

If you want to verify that, try this:

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

if (false && saySomething())
{
    echo 'statement evaluated to true';
}
Zach Rattner
  • 20,745
  • 9
  • 59
  • 82
  • 30
    Short circuit evaluation != lazy. –  Apr 17 '11 at 16:35
  • 1
    @delnan: This is an example of lazy evaluation. See http://books.google.com/books?id=vogP3P2L4tgC&pg=PA367#v=onepage&q=lazy&f=false. – Zach Rattner Apr 17 '11 at 16:36
  • 1
    A *tiny* example, and an arguable one (in the same vein, one could call if statements an example of lazy evaluation). Lazy evaluation is much more general - it applies to *every* expression *everywhere* (although you can usually force evaluation without using the value). That book excerpt gets this right. –  Apr 17 '11 at 16:39
  • 1
    Do you know of any ways to disable this behaviour ? – Radu Murzea Oct 31 '13 at 09:50
  • 5
    @RaduMurzea: short circuiting is not something I expect to be toggled as it can have adverse consequences to an entire program and imported libraries. consider the situation where you check if a variable is set before reading it `if (isset($var['index']) && $var['index'] === "something")`. if you need to evaluate each condition in a boolean expression, then evaluate and save them before the if statement, then check the results in the if condition. – Justin C Nov 01 '13 at 04:21
  • Actual answer to OP question is "Yes", not "No." Yes it short circuits, no it does not check later conditions.... – kevinc Sep 08 '16 at 16:35
  • Thanks for the heads up, @kevinc. The question has been edited since I posted my answer so I had to update my answer. – Zach Rattner Sep 08 '16 at 22:02
11

Bitwise operators are & and |. They always evaluate both operands.

Logical operators are AND, OR, &&, and ||.

  • All four operators only evaluate the right side if they need to.
  • AND and OR have lower precedence than && and ||. See example below.

 

From the PHP manual:

// 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;

In this example, e will be true and f will be false.

Das_Geek
  • 2,775
  • 7
  • 20
  • 26
Steve Douglas
  • 185
  • 2
  • 4
  • 8
    *"AND and OR always evaluate both operands."* -- this is not true. They only have lower precedence than `&&` and `||` but other than that they have the same semantic as `&&` and `||`. – axiac Sep 13 '17 at 09:17
  • 1
    will add good notice from manual: "Note that PHP's boolean operators *always* return a boolean value... as opposed to other languages that return the value of the last evaluated expression." – Hebe Oct 28 '21 at 21:16
11

Yes, it does. Here's a little trick that relies on short-circuit evaluation. Sometimes you might have a small if statement that you'd prefer to write as a ternary, e.g.:

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

Can be re-written as:

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

But then what if the yes block also required some function to be run?

    if ($confirmed) {
        do_something();

        $answer = 'Yes';
    } else {
        $answer = 'No';
    }

Well, rewriting as ternary is still possible, because of short-circuit evaluation:

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

In this case the expression (do_something() || true) does nothing to alter the overall outcome of the ternary, but ensures that the ternary condition stays true, ignoring the return value of do_something().

beppe9000
  • 1,056
  • 1
  • 13
  • 28
Robert
  • 629
  • 7
  • 8
6

Based on my research now, PHP doesn't seem to have the same && short circuit operator as JavaScript.

I ran this test:

$one = true;

$two = 'Cabbage';

$test = $one && $two;

echo $test;

and PHP 7.0.8 returned 1, not Cabbage.

agm1984
  • 15,500
  • 6
  • 89
  • 113
  • 4
    I think `&&` causes php to cast everything into a boolean, so that `$two` is cast to `true`, and then echoed as `1`. You would need `true||(echo 'no short circuit')` to test that (or something like it). – Teepeemm Jul 11 '19 at 19:21
3

No, it doesn't anymore check the other conditions if the first condition isn't satisfied.

Obay
  • 3,135
  • 15
  • 55
  • 78
2

I've create my own short-circuit evaluation logic, unfortunately it's nothing like javascripts quick syntax, but perhaps this is a solution you might find useful:

$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

I can not recall where I got the following logic from, but if you do the following;

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

You can skip having to write the true condition variable again, after the question mark, e.g:

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

As very important observation, when using the Ternary Operator this way, you'll notice that if a comparison is made it will just pass the value of that comparison, since there isn't just a single variable. E.g:

$num = 1;
$num2 = 2;
var_dump( ($num < $num2) ? : 'oh snap' );
// outputs bool 'true'
Perspective
  • 642
  • 5
  • 12
  • 2
    That logic with the `?:` works just like JavaScript/Perl's `||`. – trysis May 10 '16 at 14:48
  • Not quite trysys -- the left hand argument seems to be scanned for an expression which is returned if it is true -- regardless of a function around it. (Ex: isset($var) ?: '1' produces $var if the first expression in true). – Gerard ONeill May 19 '17 at 21:55
-5

My choice: do not trust Short Circuit evaluation in PHP...

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

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

The second part in the condition 1 || saySomething() is irrelevant, because this will always return true. Unfortunately saySomething() is evaluated & executed.

Maybe I'm misunderstood the exact logic of short-circuiting expressions, but this doesn't look like "it will do the minimum number of comparisons possible" to me.

Moreover, it's not only a performance concern, if you do assignments inside comparisons or if you do something that makes a difference, other than just comparing stuff, you could end with different results.

Anyway... be careful.

Beto Aveiga
  • 3,466
  • 4
  • 27
  • 39
  • That might be the reason for whether it's about short-circuit evaluation or eagerness. It stops as soon as it knows the result will be false. – grantwparks Jun 12 '12 at 23:15
  • 8
    Actually I just ran your code and it didn't execute saySomething(). PHP 5.3.13 – grantwparks Jun 16 '12 at 22:50
  • 3
    +1 to grantwparks, saySomething() does *not* get executed. PHP properly short circuits. I've been writing this sort of code in PHP for the better part of a decade now, I don't recall ever getting hung up on this issue. Occasionally I write more verbose code if I feel a little extra clarity is important, but usually a code comment is enough to cover that concern. – Jason Dec 10 '12 at 16:18
  • 5
    You are right. I ran my own test again and function saySomething() never gets executed. I don't know what could went wrong in my first tests. Sorry :( – Beto Aveiga Dec 26 '12 at 23:22
  • 1
    Its a proof that php behaviour is consistent. if first value in OR condition is true its obvious if is true it does not process rest of statements its consistent with short circuit behaviour. – Faraz Oct 19 '16 at 10:54
  • Rewording the second print statement reveals the answer more clearly... ``` function saySomething() { print ('hi!'); return true; } if (1 || saySomething()) { print('goodbye'); } ``` – chillywilly Sep 28 '22 at 03:15
-6

Side note: If you want to avoid the lazy check and run every part of the condition, in that case you need to use the logical AND like this:

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

This is useful when you need for example call two functions even if the first one returned false.

Patricio Rossi
  • 167
  • 2
  • 5
  • 3
    This is not "the logical AND", it's a bitwise operator. And it may surprise you, because it does *not* work exactly like the logical `&&`. – deceze Aug 10 '16 at 10:18
  • 1
    It is the logic AND gate, why you say is not? and yes as I said is not the && or AND. It will not surprise me because I actually know how it works. Simple like checking this table and using the correct return type: 1 & 1 = 1 1 & 0 = 0 0 & 1 = 0 0 & 0 = 0 – Patricio Rossi Mar 05 '17 at 21:08
  • 2
    There's a distinction between the *logical* and the *bitwise* AND in PHP; this here is *not* the logical AND. And even if *you* know what its rules are, future readers may not. – deceze Mar 06 '17 at 06:56
  • 1
    This is "not" the logical operation asked by OP. Using a single & is a bitwise operation. – GraSim Apr 18 '17 at 11:11
  • 1
    You are speaking about operators and I speaking about gates, in PHP both operators are an AND gate, but one is short circuited. – Patricio Rossi Apr 19 '17 at 15:53
  • 1
    This answer is plain wrong. If `$a == 1` and `$b == 2` then both `$a` and `$b` are not `FALSE` but `$a & $b == FALSE`. – axiac Sep 13 '17 at 16:05
  • @axiac your statement is wrong: $a = 1; $b = 2; if ($a == 1 & $b == 2) is true, if ($a & $b) is false – Patricio Rossi Sep 15 '17 at 17:23
  • Both my expression an yours need some parentheses. I reformulate mine. Check it here: https://3v4l.org/MCKGA then read about PHP [logical operators](http://php.net/manual/en/language.operators.logical.php) and [bitwise operators](http://php.net/manual/en/language.operators.bitwise.php). – axiac Sep 15 '17 at 18:15
  • 1
    Still wrong, you need to read everything, what I said is: If you need to check the result of both CONDITIONS. Looks like you think that I comparing variables, but I didn't. In your example, you are using two variables (bitwising) and that is not what I mean, I using two CONDITIONS that maybe be the result of a function call and they are BOOLEAN. – Patricio Rossi Sep 16 '17 at 18:54
  • Regardless of your arguments, it's simply incorrect to say that a single ampersand (`&`) is a logical operator when in fact it is a bitwise operator. Gates (and your related assumption regarding short circuiting) are irrelevant: it does not matter HOW an engine that implements a high-level language specification works, as long as it comes up with the correct 'result' as specified (that's where the optimization-fun is for implementers). Without significant extra explanation you seriously confuse the target-audience who are on the 'level' where they ask if php has short circuit evaluation. – GitaarLAB Nov 02 '17 at 08:10
  • `Bitwise operators allow evaluation and manipulation of specific bits within an integer`. An integer-typed-*value* is NOT a boolean-typed-*value*. It doesn't matter if a value is referenced by a variable or constant or literal or ... A variable is NOT limited to integers as your last comment might lead others to believe. `FALSE !== 0` and `TRUE !== 1`. A bitwise operator requires it's LHS and RHS argument values to be silently casted to an integer (Type coercion) when needed (and possible) so that the mathematical (not logical) operation can do it's work. – GitaarLAB Nov 02 '17 at 08:10
  • still wrong, he is asking for something and I answered, It does not matter if correct or wrong to do it, he need to know how to avoid that, I answered, also I'm comparing Boolean and that works, period, and I using the & as a gate, yes In that case I using it >>AS<< logical operator, and your ARE OFF-TOPIC. – Patricio Rossi Nov 04 '17 at 23:16
  • 1
    There's nothing off-topic about comments exclusively addressing an answer's content and/or it's comments. My comments exist mainly to help clarify both your answer and resulting discussion to the (future) target-audience of this question. No-one said it's 'wrong to do it', instead, others and myself have merely tried to patiently explain to you that the language (grammar/terminology) in your answer (the logical AND) does not convey the message (distributed across your comments) you are trying to give (which incidentally is not an answer to the question but a side note as you stated yourself). – GitaarLAB Nov 07 '17 at 00:30
  • my side note was more than clear, if he need to bypass the check of two conditions or booleans (not ints, not floats just bools), do like I wrote, anyway looks like several "easy trigger" down voted my comment (not sure why) people need to start reading more instead of down voting... – Patricio Rossi Nov 08 '17 at 23:52
  • Stating both "conditions" of a bitwise operation are evaluated is a non-sequitur. Bitwise operations do not involve Boolean conditions, so of course shortcut circuit evaluation doesn't apply. This answer is just plain wrong. – Jon Aug 23 '18 at 05:46
  • wrong or not is not the point, you get both functions executed and the condition evaluated, all this drama for a side note :( – Patricio Rossi Aug 31 '18 at 23:11