2

转自我的github

语法

&:and,按位与。以$a & $b为例,将$a和$b转化为二进制后,都为1的位设为1。

程序

$a = 6;
$b = 3;

var_dump($a & $b);

输出int(2)

原理

  • $a = 6转化为2进制为110

  • $b = 3转化为2进制为11

  • $a & $b即是 11011

  • 将$a和$b中都为1的位设为1,位数不够的补0.即110011

  • 运算结果010,转化为十进制结果为2

应用

需求

这是一个设置消息提醒的功能。我们假设这是一个blog系统,用户希望有人收藏自己的文章后,可以得到一个消息提醒。

这里有三种提醒方式:邮箱提醒、短信提醒、微信公众号提醒,用户可以通过开关按钮控制某种提醒方式是开启还是关闭。可以参考以下表格:

提醒操作 邮箱 短信 微信公众号
文章被收藏 开关按钮 开关按钮 开关按钮
被关注 开关按钮 开关按钮 开关按钮
有人评论 开关按钮 开关按钮 开关按钮

实现

1、数据库设计,表名(remind):

字段 数据类型 默认值
collection(文章被收藏) int default(0)
followed(被关注 ) int default(0)
commented(有人评论) int default(0)

2、在Remind Model中设置执行操作的提醒方式类型:

cosnt REMIND_NO = 0;//关闭所有的提醒 
cosnt REMIND_EMAIL = 1;//邮箱提醒 2的0次方  转化为二进制是:1
cosnt REMIND_SMS = 2;//短信提醒 2的1次方    转化为二进制是:10
cosnt REMIND_WECHAT = 4;//微信公众号提醒 2的2次方 转化为二进制是:100

如果有新的提醒方式值应为4816,依次类推,2的n次方

仔细观察二进制转化后

  • email第一位是1,sms第二位是1,wechat第三位是1.

  • 即email占领了第一位、sms占领了第二位、wechat占领了第三位

  • 1,代表开启提醒;0,代表关闭提醒

  • 如果第一位是1,表示开启邮箱提醒;如果第一位是0,表示关闭邮箱提醒

假设用户希望有人评论他的文章时,收到来自系统的提醒:

  • 只开启邮箱提醒,那数据库中commented字段对应的值应是:1;转化为二进制:1

  • 只开启短信提醒,那数据库中commented字段对应的值应是:2;转化为二进制:10

  • 只开启微信公众号提醒,那数据库中commented字段对应的值应是:4;转化为二进制:100

  • 如果开启邮箱提醒和短信提醒,那数据库中commented字段对应的值应是:1+2=3;转化为二进制:11

  • 如果开启邮箱提醒和微信公众号提醒,那数据库中commented字段对应的值应是:1+4=5;转化为二进制:101

  • 如果开启短信提醒和微信公众号提醒,那数据库中commented字段对应的值应是:2+4=6;转化为二进制:110

  • 如果开启所有提醒,那数据库中commented字段对应的值应是:1+2+4=7;转化为二进制:111

重点来了,前方高能,请注意啦~

3、控制器中写具体业务逻辑:

用户希望有人关注他后,可以通过邮箱提醒他,所以用户开启了邮箱提醒:

  • 前端传值:['option'=>'followed','type'=>'email'];

  • 后端接收到参数,从数据库中找到当前用户的这一条数据,得知followed字段值为0;

  • email对应的值为1,进行&运算,判断email提醒是否开启

  • 1&0=0,所以未开启,那我们要开启email提醒,此时followed=0+1=1;

后来用户觉得短信提醒比较直接,所以又开启了短信提醒:

  • 前端传值:['option'=>'followed','type'=>'sms'];

  • 后端接收到参数,从数据库中找到当前用户的这一条数据,得知followed字段值为1;

  • sms对应的值为2,进行&运算,判断sms提醒是否开启

  • 2&1=0,所以未开启,那我们要开启sms提醒,此时followed=2+1=3;

后来该用户越来越厉害,每天关注他的人特别多,每天都收到很多消息,所以他又想关闭短信提醒:

  • 前端传值:['option'=>'followed','type'=>'sms'];

  • 后端接收到参数,从数据库中找到当前用户的这一条数据,得知followed字段值为3;

  • sms对应的值为2,进行&运算,判断sms提醒是否开启

  • 2&3=2,所以已开启,那我们要关闭sms提醒,此时followed=3-2=1;

部分程序代码:

$option = $GET['option'];//提醒操作,由前端传来的值
$type = $GET['type'];//提醒方式,由前端传来的值

$remind = Remind::model()->find(1);//根据条件,在数据库中找到的一条记录

// 如果是提醒方式一
if ($type == "sms") {
    if ($remind->$option & Remind::REMIND_SMS) {
        // true 代表已开启sms提醒,此时应关闭sms提醒
        $remind->$option -= Remind::REMIND_SMS;
    } else if (!($remind->$option & Remind::REMIND_SMS)) {
        // false 代表已关闭sms提醒,此时应开启sms提醒
        $remind->$option += Remind::REMIND_SMS;
    }
}

总结

采用&运算的好处:

  • 减少了数据库设计的复杂性,一张表即可搞定;不用一张表纪录操作,另一张表纪录提醒方式,然后再关联;

  • 减少前端的判断,前端只需将当前的操作和其对应的值传给后端即可。

扩展

判断某int型变量是奇数还是偶数

以$a为例

  • $a & 1 = 0,偶数

  • $a & 1 = 1,奇数

$a = 9时:

  • $a & 1转化为2进制,1001&0001

  • 结果为0001,转化为十进制为,1,所以是奇数

$a = 16 时:

  • $a & 1转化为2进制,10000&00001

  • 结果为00000,转化为十进制为,0,所以是偶数

仔细观察,将十进制转化为二进制,当第一位为1的都是奇数,第一位为0的都是偶数


缘莲度
300 声望26 粉丝

谈梦想太大。我只想坚持每天学点知识。做点有趣的事情,做点自己喜欢的事情。这就是我的生活~