dongxiansi0158 2011-03-21 16:23
浏览 36
已采纳

改进这个PHP位域类的设置/权限?

I have been trying to figure out the best way to use bitmask or bitfields in PHP for a long time now for different areas of my application for different user settings and permissions. The farthest I have come so far is from a class contributed by svens in the Stack Overflow post Bitmask in PHP for settings?. I have slightly modified it below, changing it to use class constants instead of DEFINE and making sure the get method is passed an int only. I also have some sample code to test the class's functionality below.

I am looking for any suggestions/code to improve this class even more so it can be used in my application for settings and in some cases user permissions.

Answered in the comment below by mcrumley

In addition, I have a question about the numbering of my constants. In other classes and code sample for this type it will have things listed in powers of 2. However, it seems to work the same as far as I can tell even if I number my constants 1,2,3,4,5,6 instead of 1, 2, 4, 8, 16, etc. So can someone also clarify if I should change my constants?


Some ideas... I would really like to figure out a way to extend this class so it is easy to use with other classes. Let's say I have a User class and a Messages class. Both the User and Messages class will extend this class and be able to use the bitmask for their settings/permissions (along with other classes later on). So maybe the current class constants should be changed so they can be passed in or some other option? I really would rather not have to define (define('PERM_READ', 1);) in other parts of the site/script and would like to keep it somewhat encapsulated, but flexible as well; I am open to ideas. I want this to be rock solid and flexible like I said to use with multiple other classes for settings or permissions. Possibly some kind of array should be used? @Svens from my previous question linked above posted a comment with "implement some automagic getters/setters or ArrayAccess for extra awesomness. – svens" What do you think about something like that as well?

Include example source code if possible, please.

<?php

class BitField {

    const PERM_READ = 0;
    const PERM_WRITE = 1;
    const PERM_ADMIN = 2;
    const PERM_ADMIN2 = 3;
    const PERM_ADMIN3 = 4;

    private $value;

    public function __construct($value=0) {
        $this->value = $value;
    }

    public function getValue() {
        return $this->value;
    }

    public function get($n) {
        if (is_int($n)) {
            return ($this->value & (1 << $n)) != 0;
        }else{
            return 0;
        }
    }

    public function set($n, $new=true) {
        $this->value = ($this->value & ~(1 << $n)) | ($new << $n);
    }

    public function clear($n) {
        $this->set($n, false);
    }
}
?>

Example Usage...

<?php
    $user_permissions = 0; //This value will come from MySQL or Sessions
    $bf = new BitField($user_permissions);

    // Turn these permission to on/true
    $bf->set($bf::PERM_READ);
    $bf->set($bf::PERM_WRITE);
    $bf->set($bf::PERM_ADMIN);
    $bf->set($bf::PERM_ADMIN2);
    $bf->set($bf::PERM_ADMIN3);

    // Turn permission PERM_ADMIN2 to off/false
    $bf->clear($bf::PERM_ADMIN2); // sets $bf::PERM_ADMIN2 bit to false

    // Get the total bit value
    $user_permissions = $bf->getValue();

    echo '<br> Bitmask value = ' .$user_permissions. '<br>Test values on/off based off the bitmask value<br>' ;

    // Check if permission PERM_READ is on/true
    if ($bf->get($bf::PERM_READ)) {
        // can read
        echo 'can read is ON<br>';
    }

    if ($bf->get($bf::PERM_WRITE)) {
        // can write
        echo 'can write is ON<br>';
    }

    if ($bf->get($bf::PERM_ADMIN)) {
        // is admin
        echo 'admin is ON<br>';
    }

    if ($bf->get($bf::PERM_ADMIN2)) {
        // is admin 2
        echo 'admin 2 is ON<br>';
    }

    if ($bf->get($bf::PERM_ADMIN3)) {
        // is admin 3
        echo 'admin 3 is ON<br>';
    }
?>
  • 写回答

5条回答 默认 最新

  • dongwen1909 2011-03-26 00:48
    关注

    Others have helped with further explaining the bit masking bit of this, so I'll concentrate on

    "I do like the idea of making it more extensible/generic so different classes can extend this and use it for different sections, i'm just not sure how to do it yet"

    from your comment on @Charles' post.

    As Charles rightly said, you can re-use the functionality of your Bitmask class by extracting the functionality into an abstract class, and putting the actual "settings" (in this case permissions) into derived concrete classes.

    For example:

    <?php
    
    abstract class BitField {
    
        private $value;
    
        public function __construct($value=0) {
            $this->value = $value;
        }
    
        public function getValue() {
            return $this->value;
        }
    
        public function get($n) {
            if (is_int($n)) {
                return ($this->value & (1 << $n)) != 0;
            }else{
                return 0;
            }
        }
    
        public function set($n, $new=true) {
            $this->value = ($this->value & ~(1 << $n)) | ($new << $n);
        }
    
        public function clear($n) {
            $this->set($n, false);
        }
    }
    
    class UserPermissions_BitField extends BitField
    {
        const PERM_READ = 0;
        const PERM_WRITE = 1;
        const PERM_ADMIN = 2;
        const PERM_ADMIN2 = 3;
        const PERM_ADMIN3 = 4;
    }
    
    class UserPrivacySettings_BitField extends BitField
    {
        const PRIVACY_TOTAL = 0;
        const PRIVACY_EMAIL = 1;
        const PRIVACY_NAME = 2;
        const PRIVACY_ADDRESS = 3;
        const PRIVACY_PHONE = 4;
    }
    

    And then usage simply becomes:

    <?php
    $user_permissions = 0; //This value will come from MySQL or Sessions
    $bf = new UserPermissions_BitField($user_permissions); 
    
    // turn these permission to on/true
    $bf->set($bf::PERM_READ);
    $bf->set($bf::PERM_WRITE);
    $bf->set($bf::PERM_ADMIN);
    $bf->set($bf::PERM_ADMIN2);
    $bf->set($bf::PERM_ADMIN3);
    

    And to set privacy settings, you just instantiate a new UserPrivacySettings_BitField object and use that instead.

    This way, you can create as many different sets of BitField objects as your application requires simply by defining a set of constants that represent your options.

    I hope this is of some use to you, but if not, perhaps it will be of some use to someone else who reads this.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度