Разница между & и && в PHP

Меня путают с & и &&. У меня есть две книги PHP. Один говорит, что они такие же, но другой говорит, что они разные. Я думал, что они такие же.

Разве они не такие?

Ответ 1

& побитовое И. См. Побитовые операторы. Предполагая, что вы выполняете 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

Ответ 2

Другие ответы правильные, но неполные. Ключевой особенностью логического И является то, что он короткозамкнутый, то есть второй операнд оценивается, если необходимо. В руководстве по PHP приведен пример, иллюстрирующий:

$a = (false && foo());

foo никогда не будет вызываться, так как результат известен после оценки false. С другой стороны, с помощью

$a = (false & foo());

foo будет вызываться (также результат равен 0, а не false).

Ответ 3

 

AND operation: 

& -> will do the bitwise AND operation , it just doing operation based on
      the bit values. 
&&   -> It will do logical AND operation. It is just the check the values is 
       true or false. Based on the boolean value , it will evaluation the 
       expression 

Ответ 4

Как говорят другие, один & побитно. Он в основном преобразует левое значение в его представление битов, а правую сторону - в представление битов, а затем выполняет логическое И между ними и выводит результат.

Двойной && является либо истинным, либо ложным (на некоторых языках 0 или 1), если обе левая и правая стороны являются истинными (или ненулевыми).

Я бы также добавил, что это не только PHP. Это похоже на многие другие языки, такие как C, Java, Ruby и т.д.

Ответ 5

TL; DR

Matthew answer о том, как логический оператор && - самая большая разница; логическое сравнение остановится, когда оно найдет что-то, что сломает цепочку. Кроме того, еще одна большая разница - это результат/значение результата.

Используя Logical And &&, он всегда будет возвращать логический тип/значение, true или false.

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)

Кроме того, если мы идем на уровне инструкций сборки, мы можем видеть эту разницу и то, как компилятор справляется с обработкой, поэтому логическое и && использует cmp <var>, 0 для сравнения и не выполняет выполнение, если один операнд выходит из строя; Побитовое И использует and <var1>, <var2> для поразрядного результата, а затем проверяет, имеет ли значение 0 значение. Я знаю, что этот вопрос отмечен для и поведение может отличаться от c, но я буду использовать небольшой c, чтобы показать, как работает компилятор, когда используя логические и побитовые и.

Предположим, что у нас есть программа в c, который использует как побитовые, так и логические и:

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

if (a & b)
    c = 3;

if (a && b)
    c = 4;

Компилятор сгенерирует следующие коды операций сборки (результат W32Dasm для x86, я изменил адреса памяти с именами <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 в if (a && b) мы видим, что если a == 0, то он перескакивает и не проверяет остальное операнды.

Итак, я не согласен с комментарием animuson:

Они оба одинаковы, они просто используются для двух разных вещи для выполнения той же задачи. - animuson Мар 4 '10 в 1:42

Это не одно и то же, и оба они/должны использоваться для конкретных задач в зависимости от логики/потока программ.

Ответ 6

&& выполняется & для операндов, сведенных к 1 или 0.

(Другими словами, && является побитовым оператором под оговоркой, что он меняет свои операнды. То есть логические операции являются подмножеством побитовых операций.)