位運算在 PHP 實際項目當中的高級運用

咱們首先來看一個系統中常見的需求:php

有一個廣告表,咱們要對廣告作顯示控制:laravel

  • 手動上下線。
  • 只容許 VIP 查看。

可能的表結構以下:sql

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 '廣告圖片',
  `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='廣告表';

假如後期,咱們需求更改了。須要再增長几種限制:shell

  • 已登陸用戶
  • 未登陸用戶
  • 30 天內未登陸用戶
  • 註冊 30 天的用戶

遇到這種限制條件的需求,開發同窗是否是很傷腦筋?數據庫

可能不少開發第一反應就是在表結構增長這種新增的限制條件字段。一切看來彷佛很美好。服務器

的確,這樣添加字段是最快最容易的方式。也能完成咱們的需求。架構

可是,這樣會引來以下毛病:併發

  • 每次增長限制條件。咱們都要增長字段。這種對數據庫的更動能少改就少改。畢竟,無限制的增長字段不可取。
  • 假如廣告表數據量很大。大到增長一個字段須要幾分鐘的時候,這會給數據庫服務器形成讀寫壓力。
  • 條件越多,SQL 條件語句就會愈來愈長。

那麼,還有沒有更好的方式解決這些問題呢?分佈式

答案:有!微服務

這就是咱們今天要講的按位與運算符的高級技巧。

咱們把上面的表結構改一下:

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 '廣告圖片',
  `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
//例子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>'; //8
        }else{
            echo '<span >第'.$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>';

/**
 * 一、權限應用
 * 擁有哪些權限,就把這些權限對應的數值加起來
 * 例如:版主擁有權限(增長、刪除、修改、查詢),則版主的權限值存儲爲15(8+4+2+1)
 * 而後【權限值之和】 與 【實際權限值】作【位於】比較
 * 結果是真則擁有權限
 * 結果是假則沒有權限
 *
 * 注意:權限值必須是2的N次方,從0次方開始,31次方是2147483648
 * 32次方是4294967296,已超過了經常使用int(10)最大存儲4294967295,因此必須注意權限數量(<31個)
 * 固然若是存儲格式爲bitint或varchar等能夠存儲更長數字的格式,那麼權限數量能夠繼續增長
 */
// 賦予權限值-->刪除:八、上傳:四、寫入:二、只讀: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>'; //8
}else{
    echo '<span >無刪除權限</span>'.'<br>'; //8
}
if($key & mUPLOAD){
    echo '有上傳權限'.'<br>'; //4
} else{
    echo '<span >無上傳權限</span>'.'<br>'; //4
}
if($key & mWRITE){
    echo '有寫入權限'.'<br>'; //2
} else{
    echo '<span >無寫入權限</span>'.'<br>'; //2
}
if($key & mREAD){
    echo '有隻讀權限'.'<br>'; //1
} else{
    echo '<span >無只讀權限</span>'.'<br>'; //1
}
?>

運行結果:

以上內容但願幫助到你們,不少PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們須要點擊這裏

相關文章
相關標籤/搜索