关于PHP位运算的简单权限设计

  1. 写在最前面

    最近想写一个简单的关于权限处理的东西,之前我也了解过用二进制数的位运算可以出色地完成这个任务。关于二进制数的位运算,常见的就是“或、与、非”这三种简单运算了,当然,我也查看了下PHP手册,还有“异或、左移、右移”这三个运算。记得上初中时数学老师就开始唠叨个不停了,在此我也不想对此运算再作额外的说明,直接进入正题。

  2. 如何定义权限

    将权限按照2的N次方来定义值,依次类推。为什么要这样子定义呐?这样子定义保证了每个权限值(二进制)中只有一个1,而它恰好对应一种权限。比如:define(‘ADD‘, 1); // 增加权

define(‘ADD‘, 1); // 增加权限
define(‘UPD‘, 2); // 修改权限
define(‘SEL‘, 4); // 查找权限
define(‘DEL‘, 8); // 删除权限

权限操作

权限操作其实涉及到“角色”这个概念。进行权限操作不外乎是让某个角色赋予某种权限、禁止某种权限和检测某个角色是否拥有某种权限。相对于这三个操作。可以用二进制数间的运算操作来很方便的实现。

// 给予某种权限用到“位或”运算符
$a_access = ADD | UPD | SEL | DEL; // a拥有增删改查权限
$b_access = ADD | UPD | SEL; // b拥有增改查权限
$c_access = ADD | UPD; // c拥有增改权限

// 禁止某种权限用“位与”和“位非”运算符
$d_access = $c_access & ~UPD; // d只拥有了增权限

// 检测是否拥有某种权限用到“位与”运算符
var_dump($b_access & ADD); // 1代表b拥有增权限
var_dump($b_access & DEL); // 0代表b不拥有删权限

  1. 实现简单的权限类和角色类

    运用上面的权限操作方法,可以简单地封装成一个权限类和一个角色类。

    /**
     * 简单权限类
     * @author 27_Man
     */
    class Peak_Auth {
    
        /**
         * 权限类计数器
         * 作用在于生成权限值
         *
         * @var int
         */
        protected static $authCount = 0;
    
        /**
         * 权限名称
         *
         * @var string
         */
        protected $authName;
    
        /**
         * 权限详细信息
         *
         * @var string
         */
        protected $authMessage;
    
        /**
         * 权限值
         *
         * @var int 2的N次方
         */
        protected $authValue;
    
        /**
         * 构造函数
         * 初始化权限名称、权限详细信息以及权限值
         *
         * @param string $authName 权限名称
         * @param string $authMessage 权限详细信息
         */
        public function __construct($authName, $authMessage = ‘‘) {
            $this->authName = $authName;
            $this->authMessage = $authMessage;
            $this->authValue = 1 << self::$authCount;
            self::$authCount++;
        }
    
        /**
         * 本类不允许对象复制操作
         */
        private function __clone() {
    
        }
    
        /**
         * 设置权限详细信息
         *
         * @param string $authMessage
         */
        public function setAuthMessage($authMessage) {
            $this->authMessage = $authMessage;
        }
    
        /**
         * 获取权限名称
         *
         * @return string
         */
        public function getAuthName() {
            return $this->authName;
        }
    
        /**
         * 获取权限值
         *
         * @return int
         */
        public function getAuthValue() {
            return $this->authValue;
        }
    
        /**
         * 获取权限详细信息
         *
         * @return string
         */
        public function getAuthMessage() {
            return $this->authMessage;
        }
    }
    
    /**
     * 简单角色类
     *
     * @author 27_Man
     */
    class Peak_Role {
    
        /**
         * 角色名
         *
         * @var string
         */
        protected $roleName;
    
        /**
         * 角色拥有的权限值
         *
         * @var int
         */
        protected $authValue;
    
        /**
         * 父角色对象
         *
         * @var Peak_Role
         */
        protected $parentRole;
    
        /**
         * 构造函数
         *
         * @param string $roleName 角色名
         * @param Peak_Role $parentRole 父角色对象
         */
        public function __construct($roleName, Peak_Role $parentRole = null) {
            $this->roleName = $roleName;
            $this->authValue = 0;
            if ($parentRole) {
                $this->parentRole = $parentRole;
                $this->authValue = $parentRole->getAuthValue();
            }
        }
    
        /**
         * 获取父角色的权限
         */
        protected function fetchParenAuthValue() {
            if ($this->parentRole) {
                $this->authValue |= $this->parentRole->getAuthValue();
            }
        }
    
        /**
         * 给予某种权限
         *
         * @param Peak_Auth $auth
         * @return Peak_Role 以便链式操作
         */
        public function allow(Peak_Auth $auth) {
            $this->fetchParenAuthValue();
            $this->authValue |=  $auth->getAuthValue();
            return $this;
        }
    
        /**
         * 阻止某种权限
         *
         * @param Peak_Auth $auth
         * @return Peak_Role 以便链式操作
         */
        public function deny(Peak_Auth $auth) {
            $this->fetchParenAuthValue();
            $this->authValue &= ~$auth->getAuthValue();
            return $this;
        }
    
        /**
         * 检测是否拥有某种权限
         *
         * @param Peak_Auth $auth
         * @return boolean
         */
        public function checkAuth(Peak_Auth $auth) {
            return $this->authValue & $auth->getAuthValue();
        }
    
        /**
         * 获取角色的权限值
         *
         * @return int
         */
        public function getAuthValue() {
            return $this->authValue;
        }
    }

  2. 对权限类和角色类的简单操作例子

    // 创建三个权限:可读、可写、可执行
    $read = new Peak_Auth(‘CanRead‘);
    $write = new Peak_Auth(‘CanWrite‘);
    $exe = new Peak_Auth(‘CanExe‘);
    
    // 创建一个角色 User
    $user = new Peak_Role(‘User‘);
    
    // 创建另一个角色 Admin,他拥有 User 的所有权限
    $admin = new Peak_Role(‘Admin‘, $user);
    
    // 给予 User 可读、可写的权限
    $user->allow($read)->allow($write);
    
    // 给予 Admin 可执行的权限,另外他还拥有 User 的权限
    $admin->allow($exe);
    
    // 禁止 Admin 的可写权限
    $admin->deny($write);
    
    // 检测 Admin 是否具有 某种权限
    var_dump($admin->checkAuth($read));
    var_dump($admin->checkAuth($write));
    var_dump($admin->checkAuth($exe));

时间: 2024-10-01 08:56:04

关于PHP位运算的简单权限设计的相关文章

JAVA 通过位运算进行简单的加密

我们可以通过一个简单的位运算进行简单的加密 import java.util.Scanner; public class Example{ public static void main(String[]args){ Scanner input = new Scanner(System.in); System.out.println("请输入一个英文字符或解密字符串"); //获取用户输入的字符 String password = scan.nextLine(); //使用String

ch0103 位运算,简单状压dp

题意:n个顶点带权无向图,求最短hamilton路径长度(从起点0走到终点n-1,且经过每个顶点恰好一次的路径) 在看位运算的时候做到这题,觉得状态压缩的思路挺奇特的.本来n<20,O(n!*n)的算法肯定炸了,但是可以二进制表示状态 如果将i表示为二进制,i的第j位走过就为1,没走过就为0(注意二进制位从0~n-1),此处1<=i<2^n-1 用dp[i][j]表示状态i,到达第j个城市的最小值,那么i的二进制第j位为1(到达第j个城市),且i的二进制第j位取反之后,二进制第k位为1(

位运算一些简单的应用

从0开始数 1.把0x4f 的第3位变成0:~(1<<3) & 0x4f 转为二进制: 1001111     最终结果:->  1000111 1110111   -> 反  0001000   得:~(1<<3) & 0x4f 2.把0xff 的第2位变成0和第6位变成0: 同上    ~((1<<6)+(1<<2))  同等于  ~((1<<6)+(1<<2))  & 0xff 3.把0x51

C语言原码反码补码与位运算.

目录: 一.机器数和真值     二.原码,反码和补码的基础概念     三.为什么要使用原码,反码和补码     四.原码,补码,反码再深入     五.数据溢出测试     六.位运算的运算说明     七.位运算的简单应用   一.机器数和真值 机器数(computer number)是数字在计算机中的二进制表示形式 机器数有2个特点:一是符号数字化,二是其数的大小受机器字长的限制 比如:十进制中的+6,计算机字长为8位,转换成二进制就是00000110,如果是-6,就是10000110

位运算 使用技巧

位运算简介及实用技巧(一):基础篇 什么是位运算? 程序中的所有数在计算机内存中都是以二进制的形式储存的.位运算说穿了,就是直接对整数在内存中的二进制位进行操作.比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算.举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理): 110 AND 1011 ---------- 0010  -->  2 由于位运算

算法学习 - 递归与非递归,位运算与乘除法速度比较

递归调用非递归调用 运行时间比较 结论 位运算与乘除法 结论 递归调用/非递归调用 我们都知道,很多算法,都是用递归实现的.当然它们同时也是可以用非递归来实现. 一般我们在对二叉树进行遍历的时候,还有求斐波那契数的时候,递归是非常简单的.代码容易懂,好实现. 但是递归的时候,有一个问题,就是需要压栈.为什么要压栈呢?因为当我在函数内部调用自身的时候,要中断当前的操作继续跳转到下一次的实现,而当前运行的状态要保存起来.所以就把当前状态进行压栈,等到运行到递归条件结束的时候,再弹栈. 所以递归就是需

位运算专题

首先抱来Matrix67大牛的文章(修改部分内容): 位运算简介及实用技巧(一):基础篇     去年年底写的关于位运算的日志是这个Blog里少数大受欢迎的文章之一,很多人都希望我能不断完善那篇文章.后来我看到了不少其它的资料,学习到了更多关于位运算的知识,有了重新整理位运算技巧的想法.从今天起我就开始写这一系列位运算讲解文章,与其说是原来那篇文章的follow-up,不如说是一个remake.当然首先我还是从最基础的东西说起. 什么是位运算?    程序中的所有数在计算机内存中都是以二进制的形

位运算简介及实用技巧(一):基础篇[转]

位运算简介及实用技巧(一):基础篇 原贴链接:http://www.matrix67.com/blog/archives/264 去年年底写的关于位运算的日志是这个Blog里少数大受欢迎的文章之一,很多人都希望我能不断完善那篇文章.后来我看到了不少其它的资料,学习到了更多关于位运算的知识,有了重新整理位运算技巧的想法.从今天起我就开始写这一系列位运算讲解文章,与其说是原来那篇文章的follow-up,不如说是一个remake.当然首先我还是从最基础的东西说起. 什么是位运算?    程序中的所有

Java位运算总结:位运算用途广泛《转》

前天几天研究了下JDK的Collection接口,本来准备接着研究Map接口,可是一查看HashMap类源码傻眼咯,到处是位运算实现,所以我觉得还是有必要先补补位运算知识,不然代码看起来有点费力.今天系统研究了下,现记录如下. 首先要明白一个概念,Java位运算是针对于整型数据类型的二进制进行的移位操作.主要包括位与.位或.位非,有符号左移.有符号右移,无符号右移等等.需要注意一点的是,不存在无符号左移<<<运算符.根据位运算的概念规定,我们首先需要弄明白两个问题,java有哪些数据类型