來回顧一下這些基礎知識,同時也會講位運算在 php 實際專案當中的高階技巧。
一、位運算知識回顧
php 手冊當中,專門對位運算及位運算子進行了使用介紹。
按位與運算子:&
之所以稱為位運算,指的是在運算過程中,我們會把兩組需要位運算的數值進行二進位製化,然後兩組二進位制的數字從低位向左對齊。這裡的位指的是二進位制數字的位置。而按位與運算子指的是兩組數值每一位相與,同為 1 則 結果為 1,否則為 0。
看 php 示例:
echo 1 & 3; // 輸出:1
為什麼會輸出 1 呢?
那是因為:
1 的二進位制表示結果為:01。
3 的二進位制表示結果為:11。
那麼這兩組二進位制結果對齊之後的運算流程如下:
0111
——01
從右往左進行位運算,都 為 1 則結果為1,否則為 0。結果自然是 01。而 01 轉換成十進位制就是 1 。所以,輸出的結果為 1。
再看一組示例吧:
echo 2 & 10; // 輸出:2
我們來看看運算過程:
101010
——————
0010
0010 轉換成十進位制就是 2。
一定要記得是向左對齊。或者稱為低位順位對齊模式。
如果你不會十進位制轉二進位制或二進位制轉十進位制不會。那麼,下面這兩個方法能幫助你。
echo decbin(10); // 十進位制轉二進位制。
echo bindec(10); // 二進位制轉十進位制。
2) 按位或運算子:|
這個跟上面的按位與運算子稍微有一點不同:只要兩組數字當中有只要有一位是 1 則結果就為 1。
看示例:
echo 2 | 10; // 輸出結果:10
運算過程:
101010
——————
1010
1010 的十進位制結果就是 10。
按位異或運算子:^
這個運算子比較有意思:兩組數字必須是一組 0 與 1 結果才為 1。1 與 1 和 0 與1 都是 0。
看示例:
echo 1 ^ 1; // 輸出結果:0
echo 1 ^ 0; // 輸出結果:1
1 ^ 1 運算過程:
0101
——00
1 ^ 0 運算過程:
0100
——01
這個很簡單。沒啥好說的。反正不相同就為 1,相同就為 0。
其他位運算子:~、>>、<<
~ 按位取反運算子、>> 右移運算子、<< 左移運算子。它們的運算元都是乙個。所以,與上面的兩個運算元的位運算子有著非常明顯的區別。在 php 實際程式設計當中,運用比較少。權當知識了解即可。
二、高階動用技巧
我們在上面對位運算子的知識進行了回顧。為的就是要在接下來的實際專案中怎樣運用它解決實際問題。
我們首先來看乙個系統中常見的需求:
有乙個廣告表,我們要對廣告做顯示控制:
手動上下線。
只允許 vip 檢視。
可能的表結構如下:
create tablefinger_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 existsfinger_ad
;
create tablefinger_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 個條件才能訪問就不行了。或者,乙個滿足另外乙個取反。
優點明顯,同樣缺點也很明顯。大家要根據實際情況來選用
位運算在 PHP 實際專案當中的高階運用
我們首先來看乙個系統中常見的需求 有乙個廣告表,我們要對廣告做顯示控制 可能的表結構如下 create table finger ad ad id int 11 unsigned not null auto increment comment 主鍵 ad name varchar 50 not nu...
「位運算」在實際專案中的應用,保證你能學到東西!
如果你還是不太懂位運算,請看我的文章 那些年我們一起遺忘的位運算!下面是我在這次專案中學習到的,我眼中的位運算的應用!主要是實現 通知的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...