PHP中&和&&的区别

60

我对 &&& 搞混了。我有两本 PHP 书籍,一本说它们是一样的,但另一本说它们是不同的。我原本认为它们是一样的。

它们不是一样的吗?


1
它们其实是同一件事情,只是用于完成相同任务的两种不同方式。 - animuson
6个回答

106

&是按位与运算符。请参见按位运算符。假设您执行14&7

    14 = 1110
     7 = 0111
    ---------
14 & 7 = 0110 = 6

&& 是逻辑与符号。请参阅逻辑运算符。考虑以下真值表:

 $a     $b     $a && $b
false  false    false
false  true     false
true   false    false
true   true     true

8
我会补充一下,当您比较布尔值或整数,并将结果视为布尔值时,它们看起来是相同的。 - kibibu
1
@kibibu:是的,PHP的类型转换可能会使比较复杂化。 - cletus
@kibibu,解释器是否认为它们相等?或者根据使用的哪一个运行不同的机器代码? - Pacerier
@Pacerier 它们肯定是不同的--看看示例中的返回结果。在布尔上下文(if语句)中,将采取正确的分支,但除此之外,没有任何借用彼此的东西。除了位级别... - Gerard ONeill
5
@kibibu 不完全如此。2和1(二进制10和01)为0,即假值,但是如果PHP有任何合理性,2 && 1 应该为真。 - Muzer

62
其他答案是正确的,但不完整。 逻辑与的一个关键特征是它会短路,这意味着只有在必要时才会评估第二个操作数。PHP手册给出了以下示例以说明:
$a = (false && foo());

foo 永远不会被调用,因为在求值为 false 后结果就已知了。另一方面,使用

$a = (false & foo());

foo将被调用(另外,结果是0而不是false)。


8

Matthew's answer关于逻辑与运算符&&是最大的区别;当逻辑比较找到破坏链的东西时,它将停止。另外一个重要的区别是结果类型/值

tl;dr

使用逻辑与运算符&&,它将始终返回布尔类型/值,即truefalse

false & 1 // int(0)
false && 1 // bool(false)

当返回具有逻辑结果的函数时,使用布尔类型/值非常重要,因为某些人可以使用“恒等比较运算符” === 来比较结果(这很可能发生),如果您使用类似以下内容,则会失败:

(false & 1) === false // bool(false)
(true & true) === true // bool(false)

当您需要进行逻辑比较时,尤其是从具有逻辑结果的函数返回值时,请勿使用按位与&。而是使用逻辑与&&

(false && 1) === false // bool(true)
(true && true) === true // bool(true)

比较字符时,逻辑与 && 总是会得到true的结果,即使有NUL字符,除非将其转换为整数:
'A' && 'B' // bool(true)
'A' && 0 // bool(false)
'A' && '\0' // bool(true)
'A' && (int)'\0' // bool(false)

如果您使用&符号进行按位与操作,它将得到两个字符之间按位与运算的结果所对应的字符。
'A' & 'B' // string(1) "@"

01000001 // ASCII 'A'
&
01000010 // ASCII 'B'
=
01000000 // ASCII '@'

当使用与整数字符(这是一种特殊的整数)以外的类型时,要注意使用按位与&。例如,如果您将其与实数float/double一起使用,则即使两个操作数都不是0,结果也可能为0

1.0 & 1.0 // int(1)
2.0 & 1.0 // int(0)

1.0 && 1.0 // bool(true)
2.0 && 1.0 // bool(true)

此外,如果我们深入到汇编指令级别,我们可以看到两者的区别以及编译器如何处理。逻辑与Logical And && 使用 cmp <var>, 0 进行比较,如果一个操作数失败则不继续执行;位与Bitwise And 使用 and <var1>, <var2> 得出按位结果,然后测试其是否为0值。我知道这个问题被标记为 ,而 的行为可能与 不同,但是我将使用一个小的 程序来演示编译器在使用逻辑与和位与时的行为。

假设我们有一个使用位运算和逻辑与的程序:

int a = 0;
int b = 1;
int c = 2;

if (a & b)
    c = 3;

if (a && b)
    c = 4;

编译器将生成以下汇编指令( x86的W32Dasm结果;为了简单和更易懂,我已经用<variable>名称替换了内存地址):
:0229  mov <a>, 0
:0230  mov <b>, 1
:0237  mov <c>, 2
// if (a & b) begins
:023E  mov eax, <a>
:0241  and eax, <b>        // a bitwise and b, result stored to eax
:0244  test eax, eax       // test eax and set ZeroFlag if equals to 0
:0246  je 024F             // >---  Jump if ZeroFlag is set
:0248  mov <c>, 3          //    |  or set c = 3
// if (a && b) begins            |
:024F  cmp <a>, 0          // <---  compare a to 0 and sets ZeroFlag if difference is 0
:0253  je 0262             // >---  Jump if ZeroFlag is set (a == 0)
:0255  cmp <b>, 0          //    |  compare b to 0 and sets ZeroFlag if differemce is 0
:0259  je 0262             //    |  >--- Jump if ZeroFlag is set (b == 0)
:025B  mov <c>, 4          //    |     | or set c = 4
:0262  <program continues> // <---  <---

编译器不仅在比较逻辑和按位与时使用不同的指令,而且在行:0253中,我们看到如果a == 0,则在逻辑比较中跳过并且不检查其余操作数。因此,我不同意animuson's comment

它们是相同的东西,只是用于完成相同任务的两个不同事物。 - animuson Mar 4 '10 at 1:42

它们不是相同的东西,都应该根据程序的逻辑/流程用于特定任务。

7
AND运算:
& -> 执行按位与(bitwise AND)操作,它只是基于位值进行操作。 && -> 执行逻辑与(logical AND)操作。它只是检查值是真还是假。根据布尔值,它将评估表达式。

逻辑位运算和布尔位运算有什么区别?它们是相同的。 - avasin
1
@avasin 逻辑 AND 对其操作数的布尔值执行短路(参见Matthew Flaschen的答案)and 操作,并计算出一个布尔值,而位运算 AND 对其操作数的每个单独位执行 and 操作。因此,0b0011 && 0b0110 计算结果为 TRUE,但 0b0011 & 0b0110 计算结果为 0b0010 - Lux
@avasin,没有布尔位运算 - Christos Lytras

3
正如其他人所说,单个的&是按位的。它基本上将左侧值转换为其比特表示形式,右侧也转换为其比特表示形式,然后在它们之间执行逻辑AND并输出结果。
双重的&&要么是真的,要么是假的(在某些语言中是0或1),如果左右两边都是真的(或非零)。
我还要补充一点,这不仅在PHP中如此。在许多其他语言中也是如此,例如C、Java、Ruby等等。

0

&&是对操作数进行&运算后返回结果,操作数被归约为10

换句话说,&&是一个位运算符,但需要注意的是它会改变操作数。也就是说,逻辑操作是位操作的一个子集。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接