使用场景:

  1) 判断奇数偶数

for ($i=; $i <  ; $i++) {
if($i & ){
echo $i.PHP_EOL;
}
}
//输出所有奇数

  2)快速修改状态

$status1 = ;
$status2 = ; echo $status1 ^ ; //
echo $status2 ^ ; //

  3)日常算法

<?php

//普通函数
function ip2int($ip)
{
list($ip1,$ip2,$ip3,$ip4) = explode('.', $ip);
return $ip1*pow(256, 3) + $ip2*pow(256, 2) + $ip3*256 + $ip4;
} //位运算符
function ip2int2($ip)
{
list($ip1,$ip2,$ip3,$ip4) = explode('.', $ip);
return ( $ip1 * (1<<24) ) + ( $ip2 * (1<<16) ) + ( $ip3 * (1<<8) ) + ($ip4);
} $ip = '192.168.0.192'; echo ip2int($ip).PHP_EOL;
echo ip2int2($ip).PHP_EOL;

注意点:有人问,为什么位运算不能直接这样写呢?

function ip2int2($ip)
{
list($ip1,$ip2,$ip3,$ip4) = explode('.', $ip);
return ($ip1<<24) + ($ip2<<16) + ($ip3<<8) + ($ip4);
}

  这样不是更简洁吗?  但是你可以运行一下,会惊讶的发现并不一样

为什么?  需要注意的数值型的上限  http://php.net/manual/zh/language.types.integer.php    可以通过常量 PHP_INT_MAX 来查看这个值的具体大小:   2147483647

应用
需求
这是一个设置消息提醒的功能。我们假设这是一个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 如果有新的提醒方式值应为4、8、16,依次类推,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;
}
}

  

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

手动上下线。

只允许 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='广告表';
假如后期,我们需求更改了。需要再增加几种限制: 已登录用户 未登录用户 天内未登录用户 注册 天的用户 遇到这种限制条件的需求,开发同学是不是很伤脑筋? 可能很多开发第一反应就是在表结构增加这种新增的限制条件字段。一切看来似乎很美好。 的确,这样添加字段是最快最容易的方式。也能完成我们的需求。 但是,这样会引来如下毛病: 每次增加限制条件。我们都要增加字段。这种对数据库的更动能少改就少改。毕竟,无限制的增加字段不可取。 假如广告表数据量很大。大到增加一个字段需要几分钟的时候,这会给数据库服务器造成读写压力。 条件越多,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 。把所有的条件都组合到一个字段。 那我们此时该如何写代码呢? 比如,现在要添加如下限制条件的广告: 只允许登录用户访问或已注册 天用户或是 VIP 用户才允许访问该广告。 那么,这个广告的 bit_condition 该如何设置值呢?很简单,把这几个条件的位值直接相加。此时值为:。 很多可能会很奇怪。设置为 ,我怎么知道是这几个值的和呢?如果对 Linux 系统权限熟悉的同学就很容易理解这种做法。实际上,这里运用了按位与运算的特性:任意组合相加的值不会重复。 这个理解起来有一定难度。我三两句也很难给你梳理明白。大家可以在网上深入挖掘一下这方面儿的知识。你只需要知道这一点特点即可。 那么,现在我们该如何写 SQL 呢? 示例如下: SELECT * FROM finger_ad WHERE display = AND bit_condition & = bit_condition
这条 SQL 语句当中的 对应的是当前用户针对这么多条件得到的数值。如果 bit_condition位值是与 按位与与 bit_condition 结果相同,说明条件符合。 我们通过一个字段解决了所有条件的问题。着实得感谢按位与运算符的特性。同时也对 MySQL能支持位运算符感到开心。 那么,它有什么缺点呢? 想必有经验的同学已经看出来了。这种写法只能满足包含关系。假如要实现同时满足 个条件才能访问就不行了。或者,一个满足另外一个取反。 优点明显,同样缺点也很明显。大家要根据实际情况来选用。

PHP之位运算符的更多相关文章

  1. java的布尔运算符和位运算符

    1.布尔运算符 &&  逻辑与: ||   逻辑或: !=  不等于: 三元操作符:?: :表达式为  condition?expression1:expression2(当条件为真时 ...

  2. c 语言的位运算符复习

    转载和修正,原文连接:http://www.cnblogs.com/911/archive/2008/05/20/1203477.html 位运算是指按二进制进行的运算.在系统软件中,常常需要处理二进 ...

  3. Java的算数运算符、关系运算符、逻辑运算符、位运算符

    JAVA的运算符,分为四类: 算数运算符.关系运算符.逻辑运算符.位运算符 算数运算符(9):+  -  *  /  %  ++  -- 关系运算符(6):==  !=  >  >=  & ...

  4. c语言基础表达式, 关系运算符, 逻辑运算符, 位运算符, 数据的取值范围, 分支结构(if...else, switch...case)

    1.表达式: 表达式的判断是有无结果(值), 最简单的表达式是一个常量或变量, 如:12, a, 3 + 1, a + b, a + 5 都是表达式 2.BOOL(布尔)数据类型: c语言中除了基本数 ...

  5. PHP中的运算符---位运算符、递增递减运算符、三元运算符、字符串运算符、数组运算符、类型运算符、错误控制运算符

    1.位运算符 位运算符用来对整型数的指定位进行置位,如果被操作数是字符串,则对该字符串的ASCII码值进行操作. 运算类型 运算符 举例 结果 按位与 & $a & $b 将$a 与 ...

  6. ECMAScript 位运算符

    位运算符是在数字底层(即表示数字的 32 个数位)进行操作的. 重温整数 ECMAScript 整数有两种类型,即有符号整数(允许用正数和负数)和无符号整数(只允许用正数).在 ECMAScript ...

  7. javascript运算符——位运算符

    × 目录 [1]二进制 [2]非 [3]与[4]或[5]异或[6]左移[7]右移[8]>>>[9]应用 前面的话 位运算符是非常底层的运算,由于其很不直观,所以并不常用.但是,其速度 ...

  8. PHP中为位运算符(几乎很少用)

    PHP语言里的位运算符&.|.^ .~.〈〈 .〉〉 "&" 按位与运算 按位与运算符"&"是双目运算符.其功能是参与运算的两数各对应的 ...

  9. PHP运算符:算数运算符、逻辑运算符、三目运算符、位运算符、字符串运算符。

    赋值运算符 PHP 赋值运算符用于向变量写值. PHP 中基础的赋值运算符是 "=". 这意味着右侧复制表达式会为左侧运算数设置值. _______________________ ...

  10. Java的位运算符详解实例——与(&)、非(~)、或(|)、异或(^)

    位运算符主要针对二进制,它包括了:“与”.“非”.“或”.“异或”.从表面上看似乎有点像逻辑运算符,但逻辑运算符是针对两个关系运算符来进行逻辑运算,而位运算符主要针对两个二进制数的位进行逻辑运算.下面 ...

随机推荐

  1. June 16. 2018, Week 24th. Saturday

    Success is the ability to go from one failure to another with no loss of enthusiasm. 成功,就是即使经历过一个又一个 ...

  2. 【2018.05.10 智能驾驶/汽车电子】AutoSar Database-ARXML及Vector Database-DBC的对比

    最近使用python-canmatrix对can通信矩阵进行编辑转换时,发现arxml可以很容易转换为dbc,而dbc转arxml却需要费一番周折,需要额外处理添加一些信息. 注意:这里存疑,还是需要 ...

  3. 聚类——K-means

    聚类——认识K-means算法 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 一.聚类与分类 聚类: 无监督学习.聚类是在预先不知道欲划分类的情况下, ...

  4. Linux平台上轻松安装与配置Domino

    Linux平台上轻松安装与配置Domino Domino Server的编译安装过程中需要用到libstdc++-2.9和glibc-2.1.1(或者其更高的版本)两个编译模块,它们是Linux开发编 ...

  5. Navicat 链接mysql 显示 Clinet dose not support authentication protocol request by server ;consider upgrading MySQL client

    1  在命令窗口 输入mysql -uroot -p 首先通过cmd进入mysql 2 更改加密方式 mysql> ALTER USER 'root'@'localhost' IDENTIFIE ...

  6. SQlite源码分析-体系结构

    体系结构 在内部,SQLite由以下几个组件组成:内核.SQL编译器.后端以及附件.SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),使调试.修改和扩展SQLite的内核变得更加方便.所有SQL ...

  7. golang 开发gui

    可能因为我电脑上的mingw下只有gcc,没有g++的原因,之前用walk和andlabs都不成功 最后用github上gxui的sample代码终于编译出来一个丑陋的GUI,但编译过程也提示了一堆类 ...

  8. UVA1608-Non-boring sequences(分治)

    Problem UVA1608-Non-boring sequences Accept: 227  Submit: 2541Time Limit: 3000 mSec Problem Descript ...

  9. 006_Python 异常处理

    python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.你可以使用该功能来调试python程序. 异常处理: 本站Python教程会具体介绍. 断言(Assertions) ...

  10. day93之微信推送

    python之微信推送详解 用什么推送   -邮件   -微信推送   -短信推送微信推送   -公众号(不能主动给用户发消息)    -认证的公众号:需要营业执照,需要交钱,可以发多篇文章    - ...