何时应该使用位运算符?

25

我阅读了以下Stack Overflow的问题,我了解按位和逻辑之间的区别。

然而,它们都没有解释应该何时使用按位或逻辑。

在什么情况下应该使用按位运算符而不是逻辑运算符,反之亦然?

在哪种情况下需要逐位比较?

我不是在问它们之间的区别,而是在问何时需要使用按位运算符。


2
一个是数学函数,另一个是布尔运算符。 - mario
一个用途可以是查找奇数:$number = [1, 2, 3, 4, 5]; foreach ($number as $num) { if ($num & 1) { echo $num." 是一个奇数!<br>"; } }; - Ahmad
8个回答

27

像其他编程语言一样,位运算在PHP中也非常有用。

如果需要处理可以同时具有多个状态的值,那么位运算如何?

<?php

// since we're setting constant values in base10 we must progressively double
// them since bitwise operations work in base2. you'll see why when we output
// these as binary values below.
const STATE_FOO = 1;
const STATE_BAR = 2;
const STATE_FEZ = 4;
const STATE_BAZ = 8;

// show base2 values of the above constants
echo sprintf("STATE_FOO's base2 value is %08d\n", decbin(STATE_FOO));
echo sprintf("STATE_BAR's base2 value is %08d\n", decbin(STATE_BAR));
echo sprintf("STATE_FEZ's base2 value is %08d\n", decbin(STATE_FEZ));
echo sprintf("STATE_BAZ's base2 value is %08d\n\n", decbin(STATE_BAZ));

// set state to FOO and FEZ
$state = STATE_FOO | STATE_FEZ;

echo sprintf("base10 value of \$state is %s\n", $state);
echo sprintf("base2 value of \$state is %08d\n", decbin($state));
echo sprintf("Does \$state include FOO state? %s\n", (bool)($state & STATE_FOO));
echo sprintf("Does \$state include BAR state? %s\n", (bool)($state & STATE_BAR));
echo sprintf("Does \$state include FEZ state? %s\n", (bool)($state & STATE_FEZ));
echo sprintf("Does \$state include BAZ state? %s\n", (bool)($state & STATE_BAZ));
echo sprintf("Is state equivalent to FOO and FEZ states? %s\n", ($state == (STATE_FOO | STATE_FEZ)));

输出:

STATE_FOO's base2 value is 00000001
STATE_BAR's base2 value is 00000010
STATE_FEZ's base2 value is 00000100
STATE_BAZ's base2 value is 00001000

base10 value of $state is 5
base2 value of $state is 00000101
Does $state include FOO state? 1
Does $state include BAR state?
Does $state include FEZ state? 1
Does $state include BAZ state?
Is state equivalent to FOO and FEZ states? 1

24

忘掉你脑中已有的东西。

好的,现在假设你有一些不同的角色:管理员用户访客

还有一些不同的权限:读取写入删除

让我们为权限角色创建一些位掩码。 位掩码是一系列可以用来操作或读取某种标志的位序列。如下所示:

// flags                                bitmasks
$read = 1;                              // 0001
$write = 2;                             // 0010
$delete = 4;                            // 0100

$admin = $read | $write | $delete;      // 0001 | 0010 | 0100 => 0111
$user = $read | $write;                 // 0001 | 0010 => 0011 
$guest = $read;                         // 0001 => 0001

注意1、2、4。这必须提升为双倍。否则,可能会给您带来一些尴尬的结果。
忘记那些被注释的东西。那些只是用于个别权限和角色的位序列(或位掩码)。
现在让我们创建一个方便的函数,用于检查特定角色的特定权限。
function isAllowed($role, $permissison) : bool {
    return $role & $permissison;
}

我们完成了。让我们检查所有3个角色的$delete权限。
var_dump(isAllowed($admin, $delete));  // bool(true)
var_dump(isAllowed($user, $delete));   // bool(false)
var_dump(isAllowed($guest, $delete));  // bool(false)

为什么要使用位运算呢?简而言之,位运算更快速、简洁且易于维护。此外,在复杂应用中,使用位运算始终更高效。

4
我听过的最好的答案! - Ntiyiso Rikhotso
1
易于理解,基于真实世界的例子。 - Madan Sapkota
1
好的,这应该被标记为最佳答案。以上所有答案都是为了解释什么是位运算,而不是回答问题。给出现实场景是解释何时使用它的最佳方式。 - TomSawyer
1
位运算的另一个应用是检查数字是奇数还是偶数 ($number & 1) == 1 ? 奇数 : 偶数。顺便说一句,回答很好。 - Kevin

16

位运算符 |& 和逻辑运算符 ||&& 是完全不同的。

位运算符对两个数的二进制位进行操作并返回结果。这意味着它不是一个简单的“是”或“否”的问题。如果它们用于条件语句中,它们通常作为逻辑比较的一部分被使用。例如:

if ($x & 2 == 2) {
    // The 2^1 bit is set in the number $x
}

逻辑运算符比较两个(或更多)条件/表达式,并返回真或假。你最常在条件语句中使用它们,例如ifwhile。例如:

if ($either_this || $or_this) {
    // Either expression was true
}

7

按位运算符特别用于二进制值表示的情况。

echo '0110011010' & '0101001001'; 
//0100001000

在比较方面,逻辑运算符比位运算符更受青睐,并且在 ANDXOR 操作中比位运算符稍快一些。

if(func1() && func2())

如果 func1() 返回 false,它将不会调用 func2()
if(func1() & func2())

无论函数返回的值是什么,都会调用这两个函数。

5
在大多数情况下,您可能希望使用逻辑运算符。它们用于组合逻辑条件,通常用于控制程序流程,例如 ($isAlive && $wantsToEat)
当您想要在整数的基础二进制表示上逐位执行操作时,可以使用按位运算符。例如 (5 & 3) == 7。正如其他人所建议的那样,在PHP中编写的应用程序往往不需要这样做(尽管在低级语言(如C)中需要)。

3

按位运算符在操作数字的位时非常有用。请查看这里。否则,您应该使用逻辑运算符。此外,逻辑运算符是短路的。例如,如果您有a && bafalse,则不会评估b

免责声明:我来自Java背景,但我想在PHP中也是相同的。


1

它们是两个非常不同的运算符。

当您想要同时满足两个条件时,使用逻辑运算符&&。例如,如果今天是某人的生日且他们在账户中有钱,我想打印出“生日快乐”。这通常用于组合两个或多个条件,主要用于if语句和循环条件(尽管不仅限于此)。

当您想要执行位运算(在日常PHP编程中更为罕见)时,使用位运算符&。这种情况非常罕见,您可能正在执行位掩码操作(虽然我怀疑),因此您可能只想要两个整数表示的结果,这种情况下可以说newAttribute = attribute1 & attribute2;


0
假设有这样的代码:$x = (false && some_function());,在这种情况下,$x的值将被设置为FALSE,而不会调用some_function(),因为第一个值是FALSE。
但是如果你仍然需要调用那个函数怎么办?使用$x = (false & some_function());
换句话说,&&&更耗费处理资源,因为&&不会遍历所有的值来检查它们。如果找到一个值为FALSE,它就会返回该值,而不会继续查看其他值。
在逻辑运算中,请使用&&运算符,因为它用于返回逻辑运算的值,而&用于设置一个值,在if语句中它总是返回true。

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