在PHP中使用位掩码进行设置? [英] Bitmask in PHP for settings?

查看:113
本文介绍了在PHP中使用位掩码进行设置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

位和位掩码是我一直在努力理解的东西,但是我想学习如何在PHP中使用它们进行设置和类似操作.

Bits and bitmask are something I have been struggling to understand for a while, but I would like to learn how to use them for settings and things like that in PHP.

我终于找到了一个声称完全可以做到这一点的类,而且据我所知,它似乎可以工作,但是我不确定这是否是实现此目的的最佳方法.我将使用下面的示例代码发布类文件,以按工作顺序显示该文件.

I have finally found a class that claims to do exactly that, and as I can tell, it seems to work, but I am not sure if it is the best way of doing this. I will post the class file with example code below to show it in working order.

如果您有经验,请告诉我是否可以对其进行改进,以提高性能或其他目的.我真的很想学习这一点,而且我一直在阅读它,但是到目前为止,这对我来说很难理解.

Please if you have experience, tell me if it can be improved, for performance or anything else. I really want to learn this, and I have been reading up on it, but it is a difficult one for me to grasp so far.

班级...

<?php
    class bitmask
    {
        /**
         * This array is used to represent the users permission in usable format.
         *
         * You can change remove or add valuesto suit your needs.
         * Just ensure that each element defaults to false. Once you have started storing
         * users permsisions a change to the order of this array will cause the
         * permissions to be incorectly interpreted.
         *
         * @type Associtive array
         */
        public $permissions = array(
                                    "read" => false,
                                    "write" => false,
                                    "delete" => false,
                                    "change_permissions" => false,
                                    "admin" => false
                                    );

        /**
         * This function will use an integer bitmask (as created by toBitmask())
         * to populate the class vaiable
         * $this->permissions with the users permissions as boolean values.
         * @param int $bitmask an integer representation of the users permisions.
         * This integer is created by toBitmask();
         *
         * @return an associatve array with the users permissions.
         */
        public function getPermissions($bitMask = 0)
        {
            $i = 0;
            foreach ($this->permissions as $key => $value)
            {
                $this->permissions[$key] = (($bitMask & pow(2, $i)) != 0) ? true : false;

                // Uncomment the next line if you would like to see what is happening.
                //echo $key . " i= ".strval($i)." power=" . strval(pow(2,$i)). "bitwise & = " . strval($bitMask & pow(2,$i))."<br>";
                $i++;
            }
            return $this->permissions;
        }

        /**
         * This function will create and return and integer bitmask based on the permission values set in
         * the class variable $permissions. To use you would want to set the fields in $permissions to true for the permissions you want to grant.
         * Then call toBitmask() and store the integer value.  Later you can pass that integer into getPermissions() to convert it back to an assoicative
         * array.
         *
         * @return int an integer bitmask represeting the users permission set.
         */
        function toBitmask()
        {
            $bitmask = 0;
            $i = 0;
            foreach ($this->permissions as $key => $value)
            {

                if ($value)
                {
                    $bitmask += pow(2, $i);
                }
                $i++;
            }
            return $bitmask;
        }
    }
?>

如何将权限设置/保存为位掩码值?

How do I set/save the permissions as a bitmask value?

<?php
    /**
     * Example usage
     * initiate new bitmask object
     */
    $perms = new bitmask();

    /**
     * How to set permissions for a user
     */
    $perms->permissions["read"] = true;
    $perms->permissions["write"] = true;
    $perms->permissions["delete"] = true;
    $perms->permissions["change_permissions"] = true;
    $perms->permissions["admin"] = false;

    // Converts to bitmask value to store in database or wherever
    $bitmask = $perms->toBitmask();  //in this example it is 15
    $sql = "insert into user_permissions (userid,permission) values(1,$bitmask)";
    echo $sql; //you would then execute code to insert your sql.
?>

获取位掩码值并基于位值为每个数组项返回true/false的示例....

Example of taking the bitmask value and returning a true/false for each array item based on the bit value....

<?php
    /**
     * Example usage to get the bitmask value from database or session/cache.... then put it to use.
     * $permarr returns an array with true/false for each array value based on the bit value
     */
    $permarr = $perms->getPermissions($bitmask);

    if ($permarr["read"])
    {
        echo 'user can read: <font color="green">TRUE</font>';
    }
    else {
        echo 'user can read: <font color="red">FALSE</font>';
    }

    //user can WRITE permission
    if ($permarr["write"])
    {
        echo '<br>user can write: <font color="green">TRUE</font>';
    }
    else {
        echo '<br>user can write: <font color="red">FALSE</font>';
    }
?>

推荐答案

位字段是一种非常方便,高效的工具,用于处理标志或任何一组布尔值.

Bit fields are a very handy and efficient tool for dealing with flags or any set of boolean values in general.

要了解它们,您首先需要知道二进制数是如何工作的.之后,您应该查看按位运算符上的手册条目,并确保您知道按位AND,OR和左/右移位的工作原理.

To understand them you first need to know how binary numbers work. After that you should check out the manual entries on bitwise operators and make sure you know how a bitwise AND, OR and left/right shift works.

位字段只不过是一个整数值.假设我们的位字段的大小是固定的,并且只有一个字节.计算机使用二进制数字,因此,如果我们的数字值为29,您实际上会在内存中找到0001 1101.

A bit field is nothing more than an integer value. Let's assume our bit field's size is fixed and only one byte. Computers work with binary numbers, so if the value of our number is 29, you'll actually find 0001 1101 in the memory.

使用按位与(&)和按位OR(|),您可以读出并分别设置数字的每一位.它们都接受两个整数作为输入,并分别对每个位执行AND/OR.

Using bitwise AND (&) and bitwise OR (|) you can read out and set each bit of the number individually. They both take two integers as input and perform an AND/OR on each bit individually.

要读出号码的第一位,可以执行以下操作:

To read out the very first bit of your number, you could do something like this:

  0001 1101 (=29, our number)
& 0000 0001 (=1, bit mask)
= 0000 0001 (=1, result)

如您所见,您需要一个特殊的数字,其中仅设置了我们感兴趣的位,即所谓的位掩码".在我们的例子中是1.要读出第二位,我们必须将位掩码中的一位推"到左边一位.我们可以使用左移位运算符($number << 1)或将我们的数字乘以2来做到这一点.

As you can see you need a special number where only the bit we're interested in is set, that's the so called "bit mask". In our case it's 1. To read out the second bit we have to "push" the one in the bitmask one digit to the left. We can do that with the left shift operator ($number << 1) or by multiplying our by two.

  0001 1101
& 0000 0010
= 0000 0000 (=0, result) 

您可以对我们号码中的每一位进行操作.我们的数字和位掩码的二进制与结果要么为零(表示该位未置位"),要么为非零整数(这意味着该位已置位).

You can do that for every bit in our number. The binary AND of our number and the bit mask leads either to zero, which means the bit wasn't "set", or to a non-zero integer, which means the bit was set.

如果要设置一位,则可以使用按位OR:

If you want to set one of the bits, you can use bitwise OR:

  0001 1101
| 0010 0000 (=32, bit mask)
= 0011 1101 (=29+32)

但是,当您想清除"一点时,就必须采用另一种方式.

However, you'll have to go a different way when you want to "clear" a bit.

更通用的方法是:

// To get bit n
$bit_n = ($number & (1 << $n)) != 0
// Alternative
$bit_n = ($number & (1 << $n)) >> $n

// Set bit n of number to new_bit
$number = ($number & ~(1 << $n)) | ($new_bit << $n)

起初它看起来有点神秘,但实际上很简单.

At first it might look a bit cryptic, but actually it's quite easy.

到现在,您可能已经发现位字段是一种很底层的技术.这就是为什么我建议不要在PHP或数据库中使用它们.如果您想要一堆标志可能没问题,但是对于其他任何事情,您实际上都不需要它们.

By now you probably found out that bit fields are quite a low-level technique. That's why I recommend not to use them within PHP or databases.. If you want to have a bunch of flags it's probably ok, but for anything else you really don't need them.

您发布的课程对我来说有点特殊.例如,像... ? true : false这样的东西是非常糟糕的做法.如果要使用位字段,最好定义一些常量并使用上述方法.提出一个简单的课程并不难.

The class you posted looks a bit special to me. For example, things like ... ? true : false are veery bad practice. If you want to use bit fields, you're probably better off defining some constants and use the method described above. It's not hard to come up with a simple class.

define('PERM_READ', 0);
define('PERM_WRITE', 1);

class BitField {
    private $value;

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

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

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

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


$bf = new BitField($user->permissions);

if ($bf->get(PERM_READ)) {
    // can read
}

$bf->set(PERM_WRITE, true);
$user->permissions = $bf->getValue();
$user->save();

我没有尝试过此答案的任何代码,但是即使它开箱即用,它也应该使您入门.

I didn't try any piece of code of this answer, but it should get you started even if it isn't working out of the box.

请注意,每个位字段限制为32个值.

Note that you're limited to 32 values per bit field.

这篇关于在PHP中使用位掩码进行设置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆