位运算在 PHP 实际项目当中的高级运用
我们首先来看一个系统中常见的需求:
有一个广告表,我们要对广告做显示控制:
手动上下线。
只允许 VIP 查看。
可能的表结构如下:
- CREATE TABLE `finger_ad` (
- `ad_id` int() unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
- `ad_name` varchar() NOT NULL COMMENT '广告名称',
- `ad_image_url` varchar() NOT NULL COMMENT '广告图片',
- `ad_url` varchar() NOT NULL COMMENT '广告图片URL跳转地址',
- `is_vip` tinyint() NOT NULL DEFAULT '' COMMENT '是否仅限 VIP 显示',
- `display` tinyint() NOT NULL DEFAULT '' 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() unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
- `ad_name` varchar() NOT NULL COMMENT '广告名称',
- `ad_image_url` varchar() NOT NULL COMMENT '广告图片',
- `ad_url` varchar() NOT NULL COMMENT '广告图片URL跳转地址',
- `bit_condition` INT() UNSIGNED NOT NULL COMMENT '位运算条件:1-登录可访问、2-未登录可访问、4-30天注册可访问、8-30天未登录可访问、16-未消费可访问、32-VIP可访问',
- `display` tinyint() NOT NULL DEFAULT '' 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 = AND bit_condition & = bit_condition
这条 SQL 语句当中的 3 对应的是当前用户针对这么多条件得到的数值。如果 bit_condition
位值是与 3 按位与与 bit_condition
结果相同,说明条件符合。
我们通过一个字段解决了所有条件的问题。着实得感谢按位与运算符的特性。同时也对 MySQL
能支持位运算符感到开心。
那么,它有什么缺点呢?
想必有经验的同学已经看出来了。这种写法只能满足包含关系。假如要实现同时满足 3 个条件才能访问就不行了。或者,一个满足另外一个取反。
优点明显,同样缺点也很明显。大家要根据实际情况来选用。
扩展学习文件:
- <?php
- //例子1
- echo '<h2>demo1</h2><br>';
- //定义常量
- define('D1',1);
- define('D2',2);
- define('D3',4);
- define('D4',8);
- define('D5',16);
- function showStatus($state){
- for($i= 1;$i<=5;$i++){
- $d = 'D'.$i;
- $dd = constant($d); //取对应常量的值
- if(($state & $dd) > 0){
- echo '第'.$i.'盏灯亮'.'<br>'; //
- }else{
- echo '<span style="color: red">第'.$i.'盏灯灭</span>'.'<br>';
- }
- }
- echo "sql语句写法:SELECT * FROM `table` WHERE state & {$state} = state;";
- echo '<br>';
- echo '<br>';
- }
- $state = D4;
- showStatus($state); //只开第4盏灯
- $state = D1;
- showStatus($state); //只开第1盏灯
- $state = D4 | D1;
- showStatus($state); //开第1盏灯和第4盏灯
- $state = (D4 | D2 | D1) & (~D1);
- showStatus($state); //开第1盏灯,第2盏灯和第4盏灯,然后关闭第1盏灯
- //例子2
- echo '<h2>demo2</h2><br>';
- /**
- * 1、权限应用
- * 拥有哪些权限,就把这些权限对应的数值加起来
- * 例如:版主拥有权限(增加、删除、修改、查询),则版主的权限值存储为15(8+4+2+1)
- * 然后【权限值之和】 与 【实际权限值】做【位于】比较
- * 结果是真则拥有权限
- * 结果是假则没有权限
- *
- * 注意:权限值必须是2的N次方,从0次方开始,31次方是2147483648
- * 32次方是4294967296,已超过了常用int(10)最大存储4294967295,所以必须注意权限数量(<31个)
- * 当然如果存储格式为bitint或varchar等可以存储更长数字的格式,那么权限数量可以继续增加
- */
- // 赋予权限值-->删除:8、上传:4、写入:2、只读:1
- define('mDELETE',8);
- define('mUPLOAD',4);
- define('mWRITE',2);
- define('mREAD',1);
- //vvvvvvvvvvvvv使用说明vvvvvvvvvvvvv
- //部门经理的权限为(假设它拥有此部门的所有权限),| 是位或运行符,不熟悉的就查查资料
- echo '全部权限为:'.(mDELETE|mUPLOAD|mWRITE|mREAD).'<br>';// 相当于是把上面的权限值加起来:8+4+2+1=15
- /*
- *赋予它多个权限就分别取得权限值相加,又比如某位员工拥有除了删除外的权限其余都拥有,那它的权限值是多少?
- *应该是:4+2+1=7
- */
- //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- //判断某人的权限可用,设权限值在$key中
- /*
- *判断权限用&位与符,
- */
- // 设我只有 upload 和 read 权限,则
- $key = (mUPLOAD|mREAD);//相当于是把上传、只读的权限值分别相加:4+1=5
- echo '当前权限为:'.$key.'<br>';;
- if($key & mDELETE){
- echo '有删除权限'.'<br>'; //
- }else{
- echo '<span style="color: red">无删除权限</span>'.'<br>'; //
- }
- if($key & mUPLOAD){
- echo '有上传权限'.'<br>'; //
- } else{
- echo '<span style="color: red">无上传权限</span>'.'<br>'; //
- }
- if($key & mWRITE){
- echo '有写入权限'.'<br>'; //
- } else{
- echo '<span style="color: red">无写入权限</span>'.'<br>'; //
- }
- if($key & mREAD){
- echo '有只读权限'.'<br>'; //
- } else{
- echo '<span style="color: red">无只读权限</span>'.'<br>'; //
- }
- ?>
运行结果:
位运算在 PHP 实际项目当中的高级运用的更多相关文章
- EF架构~为分组添加位运算聚合方法
回到目录 我们知道在Linq里的分组groupby可以对集合中一个或者多个字段进行分组,并对其中一个属性进行聚合,而Linq为我们提供了多种聚合方法,由aver,sum,count等,而在大叔权限体系 ...
- 深入理解计算机系统(2.2)---布尔代数以及C语言上的位运算
布尔代数上的位运算 布尔代数是一个数学知识体系,它在0和1的二进制值上演化而来的. 我们不需要去彻底的了解这个知识体系,但是里面定义了几种二进制的运算,却是我们在平时的编程过程当中也会遇到的.这四种运 ...
- C语言回顾-函数和位运算
1.函数的概述 功能独立的代码块 C语言由若干函数组成 1)从定义分,库函数和用户定义函数两种 2)从返回值分,有返回值函数和无返回值函数 3)从参数分,无参函数和有参函数 2.形参和实参 1)形参定 ...
- 神奇的Noip模拟试题 T3 科技节 位运算
3 科技节 (scifest.pas/.c/.cpp) [问题描述] 一年一度的科技节即将到来.同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那 ...
- 《分销系统-原创第一章》之“多用户角色权限访问模块问题”的解决思路( 位运算 + ActionFilterAttribute )
此项目需求就是根据给用户分配的权限,进行相应的权限模块浏览功能,因为项目不是很大,所以权限没有去用一张表去存,我的解决思路如下,希望大家给点建议. 数据库用户表结构如下: 数据库表梳理: BankUs ...
- 关于C/C++中的位运算技巧
本篇文章讲述在学习CSAPP位运算LAB时的一些心得. 移位运算的小技巧 C/C++对于移位运算具有不同的策略,对于无符号数,左右移位为逻辑移位,也就是直接移位:对于有符号数,采用算术移位的方式,即左 ...
- Apriori算法-位运算-C语言
原文地址:http://blog.csdn.net/liema2000/article/details/6118423 //////////////////////////////////////// ...
- C#中缓存的使用 ajax请求基于restFul的WebApi(post、get、delete、put) 让 .NET 更方便的导入导出 Excel .net core api +swagger(一个简单的入门demo 使用codefirst+mysql) C# 位运算详解 c# 交错数组 c# 数组协变 C# 添加Excel表单控件(Form Controls) C#串口通信程序
C#中缓存的使用 缓存的概念及优缺点在这里就不多做介绍,主要介绍一下使用的方法. 1.在ASP.NET中页面缓存的使用方法简单,只需要在aspx页的顶部加上一句声明即可: <%@ Outp ...
- 136.Single Number---异或、位运算
题目链接 题目大意:给出一串数组,里面的数都是两个,只有一个数是一个,把这个只有一个的数找出来.时间复杂度最好是线性的,空间复杂度最好为O(1). 法一:利用map,空间换时间,代码如下(耗时26ms ...
随机推荐
- Linux命令——whiptail交互式shell脚本对话框
转自:交互式shell脚本对话框----whiptail指令 当你在linux环境下setup软件的时候就会有相应的对话框让你输入.虽然我们已经习惯了这种交互的方法,但是如果有一种直观的界面来输入是不 ...
- Linux标准IO和管道
Linux标准IO和管道 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.标准输入和输出 程序:指令+数据 读入数据:Input 输出数据:Output 打开的文件都有一个fd: ...
- springboot 2.x整合redis,spring aop实现接口缓存
pox.xml: <dependency> <groupId>org.springframework.boot</groupId> <artifactId&g ...
- java基础(14)---修饰符
修饰符:final .static.public.protected.private.default. 一.final(不能修改) 使用final修饰变量定义:该变量一旦被初始化之后就不允许再被修改. ...
- 鸡尾酒排序Cocktail Sort (双向冒泡排序)
鸡尾酒排序 鸡尾酒排序思路,先从左边开始进行冒泡排序,第一趟冒泡排序完,最大值在的数组的最右端,然后进行第二趟排序,第二趟排序从右边开始排序,第二趟结束时,最小值在数组最左端,以此类推,每一趟排序完都 ...
- Docker创建mysql镜像
原文: https://blog.csdn.net/uk8692/article/details/49386679 https://blog.csdn.net/qq362228416/article/ ...
- 使用Zookeeper实现负载均衡原理
思路 使用Zookeeper实现负载均衡原理,服务器端将启动的服务注册到,zk注册中心上,采用临时节点.客户端从zk节点上获取最新服务节点信息,本地使用负载均衡算法,随机分配服务器. 创建项目工程 M ...
- 使用postman开发testcases记录贴
我使用了两个版本的postman: Postman-linux-x64-7.1.1 这是目前(2019)最新版本.这个版本也有坑: (因为系统崩溃重装了,所以目前只有最新版本.本文截图都是这个版本的截 ...
- 1129. Shortest Path with Alternating Colors
原题链接在这里:https://leetcode.com/problems/shortest-path-with-alternating-colors/ 题目: Consider a directed ...
- 洛谷 UVA12101 Prime Path 题解
一道经典的BFS 用四个for搜索四位就行了,只要能推出怎么只变4位中的一位就很水了 #include<iostream> #include<cstring> #include ...