大张小站

  1. @八角石

    欢迎关注我的新浪微博 @八角石 !

    [ 更多详情 ]

  2. 人生

    自歌自舞自开怀,且喜无拘无碍。

  3. 心境

    若得心净如明月,长空万里了无尘。

  4. 情渊

    他生莫做有情痴,人间无地著相思。

  • 1
  • 2
  • 3
  • 4
1,665

PHP位运算符与位运算实例

PHP
分类 网站技术/村民张先生 发布于 2017-03-12 09:23
0

位运算符允许对整型数中指定的位进行求值和操作。

例子 名称 结果
$a & $b And(按位与) 将把 $a 和 $b 中都为 1 的位设为 1。
$a | $b Or(按位或) 将把 $a 和 $b 中任何一个为 1 的位设为 1。
$a ^ $b Xor(按位异或) 将把 $a 和 $b 中一个为 1 另一个为 0 的位设为 1。
~ $a Not(按位取反) 将 $a 中为 0 的位设为 1,反之亦然。
$a << $b Shift left(左移) 将 $a 中的位向左移动 $b 次(每一次移动都表示“乘以 2”)。
$a >> $b Shift right(右移) 将 $a 中的位向右移动 $b 次(每一次移动都表示“除以 2”)。

PHP位运算实例(原创)

当我们需要将多项用户权限、状态合并记录到一个数据表字段中时,可以先用二进制数字表示,然后再转换为十进制存储到数据表中。而当需要修改这个字段时,就需要用到位运算(相当于取出十进制数转换成二进制,然后进行相应替换后,转换回十进制存储到数据库中)。

例如:

用户有12项权限(或状态)需要记录,我们可以用一个12位的二进制数字表示,每一位代表一种权限(供其他程序读取使用),1表示具有该权限,0表示不具备该权限。

#B 0000 0000 0001 //权限A (十进制数1)
#B 0000 0000 0010 //权限B (十进制数2)
#B 0000 0000 0100 //权限C (十进制数4)
……(自行记录每一位为1时的十进制数,作为后面增减该权限时需要用到的参与位运算的数值*)

********************

*附:PHP自带的进制转换函数 base_convert

base_convert('100000000000',2,10);

其中2代表数值当前进制,10为需要转换的进制。两者都不能超过36(10个数字和26个数字组合),如果需要更高进制的转换,可参考 PHP 10进制与62进制互转

********************

当我们首次赋予用户某项权限时,例如赋予权限B(0000 0000 0010),对应的十进制数是2,将其记录到数据表中。
以后当我们需要增减某项权限时,例如权限C(0000 0000 0100),对应的十进制数是4,我们可以取出数据表中原有权限2,将其与要增减的4进行位运算:

$qx = 2; //数据库中取出的原有权限
$bg = 4; //要增减的权限(上文下划线处记录的值)

$qx | $bg = 6; //位运算后得到的结果(代表具有权限B和权限C),记录到数据表中
其中用到了运算符 | (按位或),表示把 $qx 和 $bg 中任何一个为 1 的位设为 1,实际运算过程是:
#B 0000 0000 0010 (2的二进制)
#B 0000 0000 0100 (4的二进制)
| 按位或:任何一个为1的位设为1,得到
#B 0000 0000 0110 (转换为十进制即为6)

下面来进行逆操作,当前用户具有权限B和权限C,数据库中记录为6,二进制数为 0000 0110 ,我们要将权限B(二进制0000 0010/十进制2)去掉,即 0000 0100 :

$qx = 6; //数据库中取出的原有权限
$bg = 2; //要增减的权限(上文下划线处记录的值)

在Discuz! X3中,我们留意到它使用了 ^ 运算符(按位异或)来去掉某种状态(或权限),详见……
我们先来试试这个运算符:

$qx ^ $bg = 4;
运算过程是:
#B 0000 0000 0110 (6的二进制)
#B 0000 0000 0010 (2的二进制)
^ 按位异或,将两者中一个为 1 另一个为 0 (两者相同的位数上数值不同)的位设为 1,否则为0
#B 0000 0000 0100 (转换为十进制即为4)

这是一个正确结果。那使用这个运算符就没有问题吗?在一种情况下是不行的!
例如,用户本就不具有某项权限,我们还错误地去执行去掉这项权限时,就会出错!

假设用户本不具有权限A(二进制0000 0000 0001/十进制1),我们看看使用 ^ 去掉这项权限会有什么结果:

$qx = 6; //数据库中取出的原有权限
$bg = 1; //要“去掉”的本就不存在权限

$qx ^ $bg = 7; //这是我们需要的正确结果吗?看看!
#B 0000 0000 0110 (6的二进制)
#B 0000 0000 0001 (1的二进制)
^ 按位异或,将两者中一个为 1 另一个为 0 (两者相同的位数上数值不同)的位设为 1,否则为0
#B 0000 0000 0111 (转换为十进制为7)
本要“去掉”权限A,现在反倒增加上去了!很显然这不是我们要的结果!

怎么解决呢?我们可以试试先对要“去掉”的权限用 ~ 取反,然后用 & 按位与:

$qx & ~ $bg = 6;
实际计算过程:
#B 0000 0000 0110 (6的二进制)
#B 0000 0000 0001 (1的二进制)
先用 ~ 对要去掉的权限取反,得到:
#B 1111 1111 1110
再用 & 按位与(将两者中都为 1 的位设为 1)
#B 0000 0000 0110 (6的二进制)
我们可以看到结果没变,因为我们是错误“去掉”本就不具有的权限,所以最后正常结果应该是不产生变化。

再来验证 &~ 能否正常去掉存在的某项权限,还是以刚才 ^ 执行成功的情况为例:

$qx = 6; //数据库中取出的原有权限
$bg = 2; //要增减的权限(上文下划线处记录的值)
$qx ^ $bg = 4; //前面 ^ 的运算结果
$qx & ~ $bg = 4; //用 &~ 的运算结果
运算过程是:
#B 0000 0000 0110 (6的二进制)
#B 0000 0000 0010 (2的二进制)
先用 ~ 对要去掉的权限取反,得到:
#B 1111 1111 1101
再用 & 按位与(将两者中都为 1 的位设为 1)
#B 0000 0000 0100 (转换为十进制即为4)

更多参考:http://php.net/manual/zh/language.operators.bitwise.php

欢迎转载分享,转载请注明 来源:大张小站 https://www.vdazhang.com/wenzhang-1789.html
若您喜欢这篇文章,欢迎订阅大张小站以获得最新内容。 / 欢迎交流探讨,请发电子邮件至 mail[at]vdazhang.com 。


欢迎谈谈你的看法(无须登录) *正文中请勿包含"http://"否则将被拦截