我们首先来看一个系统中常见的需求:

有一个广告表,我们要对广告做显示控制:

  • 手动上下线。

  • 只允许 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 实际项目当中的高级运用的更多相关文章

  1. EF架构~为分组添加位运算聚合方法

    回到目录 我们知道在Linq里的分组groupby可以对集合中一个或者多个字段进行分组,并对其中一个属性进行聚合,而Linq为我们提供了多种聚合方法,由aver,sum,count等,而在大叔权限体系 ...

  2. 深入理解计算机系统(2.2)---布尔代数以及C语言上的位运算

    布尔代数上的位运算 布尔代数是一个数学知识体系,它在0和1的二进制值上演化而来的. 我们不需要去彻底的了解这个知识体系,但是里面定义了几种二进制的运算,却是我们在平时的编程过程当中也会遇到的.这四种运 ...

  3. C语言回顾-函数和位运算

    1.函数的概述 功能独立的代码块 C语言由若干函数组成 1)从定义分,库函数和用户定义函数两种 2)从返回值分,有返回值函数和无返回值函数 3)从参数分,无参函数和有参函数 2.形参和实参 1)形参定 ...

  4. 神奇的Noip模拟试题 T3 科技节 位运算

    3 科技节 (scifest.pas/.c/.cpp) [问题描述] 一年一度的科技节即将到来.同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那 ...

  5. 《分销系统-原创第一章》之“多用户角色权限访问模块问题”的解决思路( 位运算 + ActionFilterAttribute )

    此项目需求就是根据给用户分配的权限,进行相应的权限模块浏览功能,因为项目不是很大,所以权限没有去用一张表去存,我的解决思路如下,希望大家给点建议. 数据库用户表结构如下: 数据库表梳理: BankUs ...

  6. 关于C/C++中的位运算技巧

    本篇文章讲述在学习CSAPP位运算LAB时的一些心得. 移位运算的小技巧 C/C++对于移位运算具有不同的策略,对于无符号数,左右移位为逻辑移位,也就是直接移位:对于有符号数,采用算术移位的方式,即左 ...

  7. Apriori算法-位运算-C语言

    原文地址:http://blog.csdn.net/liema2000/article/details/6118423 //////////////////////////////////////// ...

  8. 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 ...

  9. 136.Single Number---异或、位运算

    题目链接 题目大意:给出一串数组,里面的数都是两个,只有一个数是一个,把这个只有一个的数找出来.时间复杂度最好是线性的,空间复杂度最好为O(1). 法一:利用map,空间换时间,代码如下(耗时26ms ...

随机推荐

  1. CSS制作华为mate8手机模型示例

    CSS制作华为mate8手机模型效果图 1.HTML代码 <!DOCTYPE html> <html> <head> <meta charset=" ...

  2. KMP算法的时间复杂度与next数组分析

    一.什么是 KMP 算法 KMP 算法是一种改进的字符串匹配算法,用于判断一个字符串是否是另一个字符串的子串 二.KMP 算法的时间复杂度 O(m+n) 三.Next 数组 - KMP 算法的核心 K ...

  3. heapq 对有序的数组列表进行整体排序

    """ 功能:实现对有序的多个数组整体排序,获取top k个最小元素 """ from heapq import * def heap_so ...

  4. es6 字符串模板拼接和传统字符串拼接

    字符串拼接是在日常开发中必不可少的一个环节. 注意:字符串可以用单引号'',或者""双引号,出于方便大家理解,文章以下内容统一使用单引号''! 如果只是一个字符串和一个变量拼接,使 ...

  5. .NET下各种可用的HTML解析组件

    做数据抓取,网络爬虫方面的开发,自然少不了解析HTML源码的操作.那么问题来了,到底.NET如何来解析HTML,有哪些解析HTML源码的好用的,有效的组件呢?   作者在开始做这方面开发的时候就被这些 ...

  6. Python基础初始之二

    1.格式化的输出 当你遇到这样的需要:字符串中想让某些位置变成动态可传入的,首先考虑用格式化输出 1.格式化输出:% 2. 格式化输出:format 3. 格式化输出:f 2.运算符 3.编码 待续

  7. 七牛云——qshell一个神奇的工具

    前言 qshell是利用七牛文档上公开的API实现的一个方便开发者测试和使用七牛API服务的命令行工具.该工具设计和开发的主要目的就是帮助开发者快速解决问题.目前该工具融合了七牛存储,CDN,以及其他 ...

  8. go 学习 (五):goroutine 协程

    一.goroutine 基础 定义 使用者分配足够多的任务,系统能自动帮助使用者把任务分配到 CPU 上,让这些任务尽量并发运作,此机制在Go中称作 goroutine goroutine 是 Go语 ...

  9. 使用vault pki engine 方便的管理证书

    vault 是一个很方便的secret .敏感数据管理工具,当前的版本已经包含了UI,使用起来很方便 以下演示一个简单的pki 管理 项目使用docker-compose 运行,为了简单使用单机开发模 ...

  10. CodeChef November Challenge 2019 Division 1题解

    传送门 AFO前的最后一场CC了--好好打吧-- \(SIMGAM\) 偶数行的必定两人平分,所以只要抢奇数行中间那个就行了 这题怎么被爆破了 //quming #include<bits/st ...