位运算在 PHP 实际项目当中的高级运用

位运算想必软件相关专业的同学应该非常清楚。非科班专业出身的也不要着急。今天博主就带着大家一起来回顾一下这些基础知识,同时也会讲位运算在 PHP 实际项目当中的高级运用技巧。

一、位运算知识回顾

在大学的时候,我们会有一门课程《计算机组成原理》。当然,每所高校的课程名称不尽相同。这个咱们先别计较。

PHP 手册当中,专门对位运算及位运算符进行了使用介绍。
https://www.php.net/manual/zh/language.operators.bitwise.php

1) 按位与运算符:&

之所以称为位运算,指的是在运算过程中,我们会把两组需要位运算的数值进行二进制化,然后两组二进制的数字从低位向左对齐。这里的位指的是二进制数字的位置。而按位与运算符指的是两组数值每一位相与,同为 1 则 结果为 1,否则为 0。

看 PHP 示例:

echo 1 & 3; // 输出:1

为什么会输出 1 呢?
那是因为:
1 的二进制表示结果为:01。
3 的二进制表示结果为:11。

那么这两组二进制结果对齐之后的运算流程如下:

01
11
——
01

从右往左进行位运算,都 为 1 则结果为1,否则为 0。结果自然是 01。而 01 转换成十进制就是 1 。所以,输出的结果为 1。

再看一组示例吧:

echo 2 & 10; // 输出:2

我们来看看运算过程:

  10
1010
——————
0010

0010 转换成十进制就是 2。

一定要记得是向左对齐。或者称为低位顺位对齐模式。

如果你不会十进制转二进制或二进制转十进制不会。那么,下面这两个方法能帮助你。

echo decbin(10); // 十进制转二进制。
echo bindec(10); // 二进制转十进制。

2) 按位或运算符:|

这个跟上面的按位与运算符稍微有一点不同:只要两组数字当中有只要有一位是 1 则结果就为 1。

看示例:

echo 2 | 10; // 输出结果:10

运算过程:

  10
1010
——————
1010

1010 的十进制结果就是 10。

3) 按位异或运算符:^

这个运算符比较有意思:两组数字必须是一组 0 与 1 结果才为 1。1 与 1 和 0 与1 都是 0。

看示例:

echo 1 ^ 1; // 输出结果:0
echo 1 ^ 0; // 输出结果:1

1 ^ 1 运算过程:

01
01
——
00

1 ^ 0 运算过程:

01
00
——
01

这个很简单。没啥好说的。反正不相同就为 1,相同就为 0。

4) 其他位运算符:~、>>、<<

~ 按位取反运算符、>> 右移运算符、<< 左移运算符。它们的操作数都是一个。所以,与上面的两个操作数的位运算符有着非常明显的区别。在 PHP 实际编程当中,运用比较少。权当知识了解即可。

二、高级运用技巧

我们在上面对位运算符的知识进行了回顾。为的就是要在接下来的实际项目中怎样运用它解决实际问题。

我们首先来看一个系统中常见的需求:
有一个广告表,我们要对广告做显示控制:

  • 手动上下线。
  • 只允许 VIP 查看。

可能的表结构如下:

CREATE TABLE `finger_ad` (
  `ad_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `ad_name` varchar(50) NOT NULL COMMENT '广告名称',
  `ad_image_url` varchar(255) NOT NULL COMMENT '广告图片',
  `ad_url` varchar(255) NOT NULL COMMENT '广告图片URL跳转地址',
  `is_vip` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否仅限 VIP 显示',
  `display` tinyint(1) NOT NULL DEFAULT '1' COMMENT '显示状态:1显示、0隐藏',
  PRIMARY KEY (`ad_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='广告表';

假如后期,我们需求更改了。需要再增加几种限制:

  • 已登录用户
  • 未登录用户
  • 30 天内未登录用户
  • 注册 30 天的用户

遇到这种限制条件的需求,开发同学是不是很伤脑筋?

可能很多开发第一反应就是在表结构增加这种新增的限制条件字段。一切看来似乎很美好。

的确,这样添加字段是最快最容易的方式。也能完成我们的需求。

但是,这样会引来如下毛病:

  • 每次增加限制条件。我们都要增加字段。这种对数据库的更动能少改就少改。毕竟,无限制的增加字段不可取。
  • 假如广告表数据量很大。大到增加一个字段需要几分钟的时候,这会给数据库服务器造成读写压力。
  • 条件越多,SQL 条件语句就会越来越长。

那么,还有没有更好的方式解决这些问题呢?
答案:有!

这就是我们今天要讲的按位与运算符的高级技巧。

我们把上面的表结构改一下:

DROP TABLE IF EXISTS `finger_ad`;
CREATE TABLE `finger_ad` (
  `ad_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `ad_name` varchar(50) NOT NULL COMMENT '广告名称',
  `ad_image_url` varchar(255) NOT NULL COMMENT '广告图片',
  `ad_url` varchar(255) NOT NULL COMMENT '广告图片URL跳转地址',
  `bit_condition` INT(11) UNSIGNED NOT NULL COMMENT '位运算条件:1-登录可访问、2-未登录可访问、4-30天注册可访问、8-30天未登录可访问、16-未消费可访问、32-VIP可访问',
  `display` tinyint(1) NOT NULL DEFAULT '1' COMMENT '显示状态:1显示、0隐藏',
  PRIMARY KEY (`ad_id`)
) ENGINE=InnoDB DEFAULT CHARSET UTF8 COMMENT='广告表';

我们把所有的条件都去掉了。增加了一个字段:bit_condition。把所有的条件都组合到一个字段。

那我们此时该如何写代码呢?

比如,现在要添加如下限制条件的广告:
只允许登录用户访问或已注册 30 天用户或是 VIP 用户才允许访问该广告。

那么,这个广告的 bit_condition 该如何设置值呢?很简单,把这几个条件的位值直接相加。此时值为:37。

很多可能会很奇怪。设置为 37 ,我怎么知道是这几个值的和呢?如果对 Linux 系统权限熟悉的同学就很容易理解这种做法。实际上,这里运用了按位与运算的特性:任意组合相加的值不会重复。

这个理解起来有一定难度。我三两句也很难给你梳理明白。大家可以在网上深入挖掘一下这方面儿的知识。你只需要知道这一点特点即可。

那么,现在我们该如何写 SQL 呢?

示例如下:

SELECT * FROM finger_ad WHERE display = 1 AND bit_condition & 3 = bit_condition

这条 SQL 语句当中的 3 对应的是当前用户针对这么多条件得到的数值。如果 bit_condition 位值是与 3 按位与与 bit_condition 结果相同,说明条件符合。

我们通过一个字段解决了所有条件的问题。着实得感谢按位与运算符的特性。同时也对 MySQL 能支持位运算符感到开心。

那么,它有什么缺点呢?

想必有经验的同学已经看出来了。这种写法只能满足包含关系。假如要实现同时满足 3 个条件才能访问就不行了。或者,一个满足另外一个取反。

当然,我们可以把所有的广告数据拿出来,取当前广告条件复合值的可能性的位值与用户属性的复合位值进行判断,是否在用户属性复合位值的集合里面。

优点明显,同样缺点也很明显。大家要根据实际情况来选用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容