逻辑运算符

表格 15-7. 逻辑运算符

例子名称结果
$a and $bAnd(逻辑与)TRUE,如果 $a 与 $b 都为 TRUE
$a or $bOr(逻辑或)TRUE,如果 $a 或 $b 任一为 TRUE
$a xor $bXor(逻辑异或)TRUE,如果 $a 或 $b 任一为 TRUE,但不同时是。
! $aNot(逻辑非)TRUE,如果 $a 不为 TRUE
$a && $bAnd(逻辑与)TRUE,如果 $a 与 $b 都为 TRUE
$a || $bOr(逻辑或)TRUE,如果 $a 或 $b 任一为 TRUE

“与”和“或”有两种不同形式运算符的原因是它们运算的优先级不同(见运算符优先级)。


add a note add a note User Contributed Notes
eddiec at stararcher dot com
02-Aug-2006 10:47
FYI, the output from jhooks example is:

Test 1 : bool(true)

Test 1b : bool(true)

Test 2 : string(3) "boo"

Test 2b : bool(true)
jhooks
12-Apr-2006 06:55
>> I have read a few of these responses and quite honestly didn't find one that explained the differences between the "||" and "OR" operators.

The difference is explained in the link to on operator precedence.

The '||' operators are evaluated before assignment ('='), whereas the 'or' operators are evaluated after the assignment.  In your second example you are telling PHP to first assign the result of '(choice1 != false ? 'hah' : 'boo')' to $val, then 'or' it against the rest of the statement.  Try the example below and you will see what I mean (note the extra brackets to enforce precedence):

<?php
 define
('choice1', false);
 
define ('choice2', "dog");
 
define ('default1', "other");
 
$val = array();

 
$val["Test 1"] = (choice1 != false ? 'hah' : 'boo') || (choice2 != false ? 'hah2' : 'boo2') || (default1 != false ? 'hah3' : 'boo3');
 
$val["Test 1b"] = ((choice1 != false ? 'hah' : 'boo') || (choice2 != false ? 'hah2' : 'boo2') || (default1 != false ? 'hah3' : 'boo3'));
 
$val["Test 2"] = (choice1 != false ? 'hah' : 'boo') or (choice2 != false ? 'hah2' : 'boo2') or (default1 != false ? 'hah3' : 'boo3');
 
$val["Test 2b"] = ((choice1 != false ? 'hah' : 'boo') or (choice2 != false ? 'hah2' : 'boo2') or (default1 != false ? 'hah3' : 'boo3'));

 foreach (
$val as $test => $result ) {
  print (
"$test : " ); var_dump ( $result ); print "<br />\n<br />\n";
 }
?>
test at hto dot com
11-Sep-2005 08:04
Because the OR shorthand for an if block can produce more
readable code with less typing, it is tempting to produce functions that will return FALSE on failure or some other data type on success. Like mysql_connect, which "Returns a MySQL link identifier on success, or FALSE on failure."

The novice php php developer should avoid creating functions which might produce a FALSE on failure and an integer on success, if there is any chance that the integer might be zero.

<?php
blah blah blah
;
$i = give_me_liberty() or die("FATAL DB ERROR!");
blah blah blah;
?>
ironmo67 at yahoo dot com
21-Jun-2005 03:12
Discovered a somewhat annoying different between PHP and Perl:

<?php
 
function some_function(){ return false; }
  if ( !
some_function() ) return false;
?>

cannot be rewritten as the prettier:

<?php
 
function some_function(){ return false; }
 
some_function() or return false;
?>

The following will work however:

<?php
 
function some_function(){ return false; }
 
some_function() or die();
?>

Can you guess why? Simply, die() is a function and 'return' is a statement (like the difference between print() and echo, sort of).  This is really to bad because I find the if(!){} version tired and unreadable, but hey, it's better than if ( some_c_function == 0) { do something }.
04-Apr-2004 12:20
A lot of the discussion below could have been avoided simply by being clear that &, | and ^ are *not* logical operators. That's why they're not listed on this page. They're operators that act on the binary representations of numbers. They do not take logical values (i.e., "true" or "false") as arguments without first converting them to the numbers 1 and 0 respectively. Nor do they return logical values, but numbers. Sure, you can later treat those numbers as though they were logical values (in which case 0 is cast to "false" and anything else is cast to "true"), but that's a consequence of PHP's type casting rules, and nothing to do with the behaviour of the operators.

If you want logical operations, use logical operators; if you want bitwise operations, use bitwise operators ... using one for the other seems like a good way to make things difficult.
kws_ at hotpop dot com
07-Feb-2004 09:32
"Just Because You Can, Doesn't Mean You Should."

I also feel that circumventing short-circuit evaluation and relying on side-effects in conditional expressions is exercising bad style. Writing code that documents itself using clear and straightforward constructs strikes me as a much better practice than using a convoluted and difficult-to-read expression and explaining it with comments (or worse yet, not documenting it at all!) Indeed, source code should be written for the programmer's eyes more so than the computer's.

Utilizing the bitwise operators in a logical context could violates the expectations of the reader and may create confusion because bitwise operators imply bit-field operands.

I also feel that assuming that short-circuit evaluation is best for logical constructs IS within the compiler's "rights", since when logical operators are used for their intended purpose, the assumptions that short-circuiting makes *ARE* logical, and do (once again, when used correctly) optimize evaluation of logical expressions.

It is not my intention to directly flame or insult any individual, but only to discourage the use of poor style and to encourage new (and even some experienced) programmers to write clear and verbose code, and to think about the programmers, rather than the computers that might end up trying to decipher your creations.
29-Jun-2003 11:12
in answer to braintreno:

The second example you brought is the correct way to do it! It is not convoluted logic at all, it is what makes your code readable by not relying on obscure side effects!! It is much easier to read than the first one and it is by far easier to maintain.

For the idea to let a CheckThisOrOther() funtion echo information to the user alone, you should be stripped of your coding licence. If i ever had to maintain on of your scripts, I'd have to hate you.

This is not meant as flame bating as it might sound! Source code is not written for computers to execute, but for coders to read! Keep that at heart and your co-workers will thank you for it!
braintrino
14-Jun-2003 02:59
shadedecho's post to force evaluation of both OR expression is actually exactly what should be done to suppress short-circuit optimization.

There are many occasions that you don't want the compiler to short-circuit any evaluation, especially when you want to do an and/or situation.  The short-circuit evaluation does an OR operation but not an AND/OR operation!!!

For instance, if I want the check the user's query form to see if the user has missed answering any entry AND/OR if the user had duplicated the same answer for more than one entry, then I need to send the form back to the client informing what I want to be corrected.

function SomeAnswersAreMissing()
{
   ...
   echo "Oops! You missed answering some questions.";
  return TRUE;
}

function SomeAnswersAreDuplicated()
{
   ...
   echo "Oops! You can answer both the same way.";
  return TRUE;
}

if (SomeAnswersAreMissing() || SomeAnswersAreDuplicated())
   SendFormAgain();

If I do that, the user will only see the missing answer warning but not the duplicated answer warning, even if both are true.  This is not informative to the user because he/she will have to re-submit the form twice before he/she realized everything he/she did wrong, and frustrate the hack out of them.  That is not user-friendly.

But if I use:

if (SomeAnswersAreMissing() | SomeAnswersAreDuplicated())
   SendFormAgain();

Then both warning messages are sent at the same time, and the user can correct it in one re-send.

Thank shadedecho, I had been looking for a way to override the compiler's stupid short-circuit optimization.  The computer cannot just assume that short-circuiting is the best :(

BTW, of course you can do:

$you_made_a_mistake = false;

if (SomeAnswersAreMissing())
   $you_made_a_mistake = true;
if (SomeAnswersAreDuplicated())
   $you_made_a_mistake = true;

if ($you_made_a_mistake)
   SendFormAgain();

But that is convoluted logic!!!
hop
24-May-2003 07:53
Dear Newbie,

(as i don't see such ideas creeping up in experienced programmers' minds...)

please don't pay attantion to shadedecho's post from 14-Mar-2003 04:02! He is heavily relying on obscure side effects, which is not only very bad programming practice, but also does not achieve the optimization he thinks it is.

The proper way to make this

if ( ($a .= blah()) || ($a .= blah2()) ) {
   echo $a;
}

work like shadedecho wants is (although the example as a whole is rather inapt):

$a .= blah();
$a .= blah2();

if ($a) { echo $a; }

If you read the discussion he links to you will find that he really wanted to get all distinct entries from two different db tables. Even there he is mistaken. The proper way to do this is to process the first table and then process the second table.
This is not only far more readable than the workaround with '|', it is also not the least slower.

Thanks.
shadedecho
15-Mar-2003 07:02
It appears (after much frustrating but ultimately helpful searching and discussion on forums like tek-tips) that the
|| and the && are "short-circuited" as has been previously noted BUT the | and & operators (documented by PHP as bitwise operators) behave as their non-short-circuited counter-parts, respectively.

ex:

function blah() {
  echo "hello< br>";
  return "from blah()< br>";
}

function blah2() {
  echo "world\< br>";
  return "from blah2()< br>";
}

$a = "";

if ( ($a .= blah()) || ($a .= blah2()) ) {
  echo $a;
}

This would result in the following output:

hello
from blah()

Notice the "world" didn't get echo'd and the "from blah2()" didn't get concat'd into the $a variable, because the first assigment to $a was successful, so the "short-circuting" kicks in and the boolean test terminates without evaluating the rest of it.

HOWEVER, if you replace || with just | in that "if" statement, you get the output:

hello
world
from blah()
from blah2()

Eureka! all parts of the boolean test are evaluated, in expected left-to-right fashion, and following all the normal precendence rules, so far as I can see.

This makes total sense...  Using the bitwise operators, what is occurring is the bitwise-level operation on the result of two non-bitwise operations (the assignments). If a non-bitwise operation returns null (in other words, the value being assigned turns out to be null or 0), the bitwise operator would bind to that (or more appropriately, would "see" it) as a "0", otherwise it would see a non-zero (string of bits with at least one "1" in it).

Then a bitwise | is done on the two values, and if either is non-zero (has "1" bits in it) then the result will have those "1" bits in it (non-zero), and the if statement will interpret any non-zero value as true in a boolean test.  Likewise, if both operands to the | were null or 0, then the result would be a zero value, which "if" would interpret as false.

The if statement above is doing a bitwise | on (in this case) two non-zero values (with "1"s in it at the bit level), so the | operation returns a non-zero value which is then reinterpreted by the if statement as TRUE!

So, in this special case where you are trying to string together non-short-circuited boolean tests, these operators work on their operands at the bitwise level, and since they are not comparison operators but mathematical operators, they can't be short-circuited, and the resulting behavior is a non-short-circuited "boolean test".

I know, you must think I am crazy for trying to get around a built-in optimization like this, but I assure you there is a very good reason for it, and if you are interested, you can check out this thread as I have a very long post in there which explains what I was trying to do:

It is the 9th post down, where you will find my description of my database query'ing which i was wanting to optimize.

http://www.tek-tips.com/gviewthread.cfm/lev2 /4/lev3/31/pid/434/qid/500825
(note i had to split that URL for the post, but it should be all together on one line obviously)
02-Mar-2002 02:11
The post of 14-Oct-1999 04:09 about operator precedence is incorrect.
When I run the second example

$choice1 = "";
$choice2 = "dog";
$default = "other";
$val = $choice1 or $choice2 or $default;

Then $val is "", since the expression is equivilent to
($val = $choice1) or $choice2 or $default;

To get $val to be "dog" use:
$val=$choice1 or $val=$choice2 or $val=$default;

which is equivilent to
($val=$choice1) or ($val=$choice2) or ($val=$default);
jesse at bend dot (spam dot me dot not dot )com
05-Oct-2001 07:30
For those who might not pay close attention to matters of Operator Precedence, the manual is not kidding when it says that "AND" and "&&" have different precedence. In particular these two forms of logical operators straddle the assignment operator (=) in precedence!

For instance,
$a = $b && $c;

is not the same as
$a = $b AND $c;

The difference is that "AND" has lower precedence than the equals sign. To whit, the last expression more closely resembles:
($a = $b) && $c

which probably isn't what you want.

This may be of aid to those who like their code to read like english, and might think that the precedence differences of these operators are relatively exotic: they aren't.

As for me I ran into this problem because there is no symbolic logical XOR (for instance, no ^^) so I had to use XOR, and then figured that in similar places I'd ought to use AND and OR, and then my code broke :)

So now I've got to
$a = ($b xor $c);

Happy Trails

- - Jesse Thompson
bend.com
yohgaki at hotmail dot com
14-Apr-2001 09:47
In PHP4, "and", "or", "&&", "||" -- all are "short circuit" like in C/C++. In PHP3, I think it was not.

"Short circuit" means language stops evaluation of expression when conditions are determined. (Most language uses short circuit evaluation for logical condition)

For example,

$a = true;
$b = false;
if ( $a || $b ) {
}

This "if" statement only evaluate $a, since $a is true and whole condition must be true. (i.e. if $b is a function instead of value, the function will not be called)
muerte at web-ster dot com
22-Jan-2001 09:41
I was hoping to find an operator similar to ||= functions in perl.  My first thought would be:

$i = $i or "default"

But or doesn't work like that.  If you want to assign a default value to your variables only if they're not already assigned you CAN however do:

$i or $i = "default"

The first example does NOT work because the or operator is not overloadable like it is in Perl.
dante at hearme dot com
14-Oct-1999 07:09
[Ed Note:  The reason for this is because || has a higher precedence than =, and = has a higher precedence than 'or'.  See  http://www.php.net/manual/en/language.operators.precedence.php
--irc-html@php.net]
I wanted to do something like this:

$choice1 = "";
$choice2 = "dog";
$default = "other";
$val = $choice1 || $choice2 || $default;

but then $val1 will only contain 1 or 0.  Instead I did this:

$choice1 = "";
$choice2 = "dog";
$default = "other";
$val = $choice1 or $choice2 or $default;

now $val contained the string "dog".  That's
weird that 'or' is different from '||'...and I would
think that the '||' should be smart enough to handle
strings...the way PERL does.  Guess not.  Maybe it's
a design choice.
dtaylor at sclug dot remove_this dot usc dot edu
31-Jul-1999 05:26
and, or, &&, || -- all are "short circuit" like in C++