我們首先來看乙個系統中常見的需求:
有乙個廣告表,我們要對廣告做顯示控制:
可能的表結構如下:
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 '廣告',
`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='廣告表';
假如後期,我們需求更改了。需要再增加幾種限制:
遇到這種限制條件的需求,開發同學是不是很傷腦筋?
可能很多開發第一反應就是在表結構增加這種新增的限制條件字段。一切看來似乎很美好。
的確,這樣新增欄位是最快最容易的方式。也能完成我們的需求。
但是,這樣會引來如下毛病:
那麼,還有沒有更好的方式解決這些問題呢?
答案:有!
這就是我們今天要講的按位與運算子的高階技巧。
我們把上面的表結構改一下:
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 '廣告',
`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 個條件才能訪問就不行了。或者,乙個滿足另外乙個取反。
優點明顯,同樣缺點也很明顯。大家要根據實際情況來選用。
擴充套件學習檔案:
<?php
//例子1
echo '
';//定義常量
define('d1',1);
define('d2',2);
define('d3',4);
define('d4',8);
define('d5',16);
function showstatus($state)else
}echo "sql語句寫法:select * from `table` where state & = state;";
echo '
'; echo '';}
$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 '
';/**
* 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).'
';// 相當於是把上面的許可權值加起來:8+4+2+1=15
/**賦予它多個許可權就分別取得許可權值相加,又比如某位員工擁有除了刪除外的許可權其餘都擁有,那它的許可權值是多少?
*應該是:4+2+1=7
*///^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//判斷某人的許可權可用,設許可權值在$key中
/**判斷許可權用&位與符,
*/// 設我只有 upload 和 read 許可權,則
$key = (mupload|mread);//相當於是把上傳、唯讀的許可權值分別相加:4+1=5
echo '當前許可權為:'.$key.'
';;if($key & mdelete)else
if($key & mupload) else
if($key & mwrite) else
if($key & mread) else
?>
執行結果:
對php後端技術,對php架構技術感興趣的朋友,我的官方群1023755567點選此處,一起學習,相互討論。
位運算在 PHP 實際專案當中的運用
來回顧一下這些基礎知識,同時也會講位運算在 php 實際專案當中的高階技巧。一 位運算知識回顧 php 手冊當中,專門對位運算及位運算子進行了使用介紹。按位與運算子 之所以稱為位運算,指的是在運算過程中,我們會把兩組需要位運算的數值進行二進位製化,然後兩組二進位制的數字從低位向左對齊。這裡的位指的是...
「位運算」在實際專案中的應用,保證你能學到東西!
如果你還是不太懂位運算,請看我的文章 那些年我們一起遺忘的位運算!下面是我在這次專案中學習到的,我眼中的位運算的應用!主要是實現 通知的3個操作 1.置頂 2.設為首頁 3.同時為 置頂 設為首頁 效果如圖 我們要想簡便的進行位運算,我們可以直接進行如下列舉定義,以2的次方定義,應為他們的值很特殊 ...
位運算在演算法中的應用
leetcode原題位址 題目描述 給定乙個整數,編寫乙個函式來判斷它是否是 2 的冪次方。解法 n n 將除最後一位的1之外的所有的數字置為0 因為 n n 1,所以n n n n 1 例如 7對應的二進位制為0111 7對應的二進位制為1001 7 7 0001 實現 public boolea...