2013-09-02 4 views
0

я обзор кода моего стажера, и я наткнулся на что-то вроде этого:Php сравнение старшинства путаница

//k* are defined constants 
if ($a == 0 & $b >= k0) $a = 1; 
if ($a == 1 & $b >= k1) $a = 2; 
if ($a == 2 & $b >= k2) $a = 3; 

Я думал, что он сделал ошибку, путая & и && (я освобожденный логическое И)

Но, по сути, его код работает как ожидается, и я не могу понять почему. На мой взгляд, >= имеет приоритет на ==, что также имеет преимущество на & (reference).

Так, я испытал (1 == 0 & 1 >= 0) и его вывод 0. Я ожидал 1, потому что на мой взгляд, это было как:

  • 1 >= 0 возвращается true,
  • Тогда 1 == 0 дает false,
  • Поэтому выражение теперь (false & true), который я думал, равно (0 & 1)
  • Который равен 1 ...
  • Значит, его & действует как ||.

Где я ошибаюсь ??

+0

@MarkBaker Он сказал это. Он пытается понять, почему сработавший код казался работать. – Barmar

+0

@MarkBaker Вот что я тоже думал, но он работает так. – Bigood

+0

'0 & 1' === 0! побитовое '&' возвращает биты, которые устанавливаются в обоих операндах. Если один из операндов равен «0», конечным результатом будет '0' –

ответ

3

В PHP побитовое И & на двух булевых преобразованиях преобразует их в целые числа (то есть один или нулевой) и выполняет И. Когда результат этой операции оценивается как логический, результат фактически эквивалентен той же функциональности, что и логический И &&.

0 & 1 // 0, false 
1 & 0 // 0, false 
1 & 1 // 1, true 
0 & 0 // 0, false 

Proof

Интерн будет ошибочно два оператора, потому что нет никаких причин, чтобы сделать это - вы теряете оценку короткого замыкания и добавить несколько ненужных приведения типов.

Но он действительно работает так же, как логический И в этом сценарии.

В теории, ваш приоритет аргумент является правильным, но это относится только тогда, когда есть неоднозначность:

$foo = $b >= k1; 
if ($a == 1 & $foo) $a = 2; 

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

$foo = $b >= k1; 
if (($a == 1) & $foo) $a = 2; 
// or 
if ($a == (1 & $foo)) $a = 2; 

... в зависимости от того, что вы хотели.

Но так как вы не можете сделать:

$foo = 0 & $b; 
if ($a == $foo >= k1) $a = 2; 

... код шоу можно интерпретировать только в одну сторону, так что это будет «безопасным», даже если это не совсем то, что вы хотели.

Тем не менее, по-прежнему очень мало опасности, если вы не начнете смешивания логические и битовые операторы - очередностью-накрест, два типа оператора находятся в непосредственной близости друг к другу, так что-то вроде:

if ($foo & $bar && $baz | $qux) // ... 

. .. в серьезной опасности сделать что-то неожиданное.

Стоит также отметить, что на самом деле & является достаточно надежным (он должен еще дать ожидаемый результат, это просто неэффективно и не будет короткое замыкание) - это |, которые могли бы начать делать странные вещи.

Однако, вы, очевидно, никогда этого не сделаете, вы бы использовали фигурные скобки, потому что эта версия довольно непрозрачна.

+0

Но на 4 бита,' 0000 & 0001 = 0001', правильно? Итак, на 1 бит, почему бы не быть '= 1'? Действительно ли php применяет другую операцию? – Bigood

+0

@Bigood Я подозреваю, что вы принимаете побитовые '' '' '' '' '' '' '' '' '' '' 0000 и 0001 == 0000'' - это биты, которые установлены на * оба * операнда, которые присутствуют в выходном значении.Число битов не имеет значения, оно применяется от lsb к msb, любые отсутствующие биты с обеих сторон считаются нулевыми (на самом деле то, что произойдет, - это приведение к более крупному типу, но в PHP все ints - это просто система 'long' в любом случае) – DaveRandom

+0

Мне стыдно, что я сделал. Сожалею! Мой стажер потряс меня. – Bigood

1

Ваша ошибка здесь:

  • Таким образом, выражение теперь (ложь & правда), который я думал, равный (0 & 1)
  • который равен 1 ...

0 & 1 фактически соответствует 0.

Булева алгебра изоморфна побитовым операторам, то есть базе двоичных компьютеров.

1

(0 & 1) является 0

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

1

Это совершенно просто. Как вы знаете, побитового & возвращает биты, которые «на» в обоих операндов:

0011 
0010 
----- & 
0010 

Поразрядный | установит все биты, которые установлены либо в один (или оба) из операндов:

0011 
0010 
----- | 
0011 

в вашем случае, true и false принуждают к Интс (0 и 1), что дает

0001 
0000 
----- & 
0000 

Это так просто

+0

Действительно. Позор мне – Bigood

+0

@Bigood: Нет необходимости: P ... вы слишком усложнили его, потому что вы привыкли к многим причудам, которые PHP (назовите его опытом с тройным оператором или что-то еще ...). Когда-нибудь ты его качнишь :) –

+1

О да, я буду ... :) Я буду учить его скобку в следующий раз – Bigood