如何在 PHP 中实现位掩码?

我不确定位掩码是否正确,让我解释一下:

在 php 中,error_reporting函数可以被多种方式调用:

// Report simple running errors
error_reporting(E_ERROR | E_WARNING | E_PARSE);


// Reporting E_NOTICE can be good too (to report uninitialized
// variables or catch variable name misspellings ...)
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);


// Report all errors except E_NOTICE
// This is the default value set in php.ini
error_reporting(E_ALL ^ E_NOTICE);

我从 php.net 页面 给你得到了位掩码这个术语

无论如何,这里的要点是,我已经实现了一个名为 ls的 SIMPLE 方法,它返回一个目录的内容。

这个函数有3个参数... ($include _ hide = false,$return _ Absol= false,$ext = false)

所以当我调用这个函数时,我设置我想要的结果。我是否希望结果返回隐藏的目录,是否我想只有基名等。

所以当我调用这个函数的时候

ls(true, false, true)
ls(false, false, true)
ls(true, true, true)
etc...

我认为如果我只标记我希望如何返回数据,它会更具可读性?

比如:

ls( INCLUDE_HIDDEN | HIDE_EXTS );
ls( SHOW_ABSOLUTE_PATHS | HIDE_EXTS );

等等。

在测试哪些标志已经被调用时,我将如何实现它?

34203 次浏览
define( "INCLUDE_HIDDEN", 0x1 );
define( "HIDE_EXTS", 0x2 );
define( "SHOW_ABSOLUTE_PATHS", 0x4 );
//And so on, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800 etc..

You can then check for individual flags in your ls function:

if( $flags & INCLUDE_HIDDEN ) { //<-- note just a single &, bitwise and
//$flags have INCLUDE_HIDDEN
}

It's quite simple actually. First a bit of code to demonstrate how it can be implemented. If you don't understand anything about what this code is doing or how it works, feel free to ask additional questions in the comments:

const FLAG_1 = 0b0001; // 1
const FLAG_2 = 0b0010; // 2
const FLAG_3 = 0b0100; // 4
const FLAG_4 = 0b1000; // 8
// Can you see the pattern? ;-)


function show_flags ($flags) {
if ($flags & FLAG_1) {
echo "You passed flag 1!<br>\n";
}
if ($flags & FLAG_2) {
echo "You passed flag 2!<br>\n";
}
if ($flags & FLAG_3) {
echo "You passed flag 3!<br>\n";
}
if ($flags & FLAG_4) {
echo "You passed flag 4!<br>\n";
}
}


show_flags(FLAG_1 | FLAG_3);

Demo


Because the flags are integers, on a 32-bit platform you define up to 32 flags. On a 64-bit platform, it's 64. It is also possible to define the flags as strings, in which case the number of available flags is more or less infinite (within the bounds of system resources, of course). Here's how it works in binary (cut down to 8-bit integers for simplicity).

FLAG_1
Dec:    1
Binary: 00000001


FLAG_2
Dec:    2
Binary: 00000010


FLAG_3
Dec:    4
Binary: 00000100


// And so on...

When you combine the flags to pass them to the function, you OR them together. Let's take a look at what happens when we pass FLAG_1 | FLAG_3

  00000001
| 00000100
= 00000101

And when you want to see which flags were set, you AND the bitmask with the flag. So, lets take the result above and see if FLAG_3 was set:

  00000101
& 00000100
= 00000100

...we get the value of the flag back, a non-zero integer - but if we see if FLAG_2 was set:

  00000101
& 00000010
= 00000000

...we get zero. This means that you can simply evaluate the result of the AND operation as a boolean when checking if the value was passed.

The others have offered good suggestions, but these days it's much more common to pass in associative arrays instead of bitmasks. It's much more readable and allows you to pass in other variables other than just true/false values. Something like this:

myFunction(['includeHidden' => true, 'fileExts' => false, 'string' => 'Xyz']);


function myFunction($options) {
// Set the default options
$options += [
'includeHidden' => false,
'fileExts' => true,
'string' => 'Abc',
];


if ($options['includeHidden']) {
...
}
...
}

I had an API I was working with - the documentation was pretty thin. It was giving us a single integer and said:

"Information is encoded in these values as a bit field. Bit fields work by storing multiple true/false values in the same integer, instead of having multiple integers for each value. To look up a value in a bitfield, you'll want to make use of Bit Masks."

Bit     Decimal Value    Setting
0       1                Display
1       2                Sell
2       4                Kiosk Display
3       8                No Passes
4       16               Dolby Digital
5       32               THX
6       64               DLP
[etc]

I figured out how to solve it based on the other answers here, and though I would share the function I came up with.

I ended up writing this function:

<?php
function bitmap_decode( $label_array, $value, $return_item ) {
$label_array = array_flip( $label_array ); // swap the keys and values
$i = $label_array[ $return_item ]; // get the decimal key value for the item on the list
$i =  2**$i; // use 2 to the nth power to get the decimal bitmap value for the item
return $value & $i ? 1 : 0; // use the & operator to determine if the value is true or false. return 1 or 0 accordingly
}

... which would parse out the values

$info1 = array(
'Display',
'Sell',
'Kiosk Display',
'No Passes',
'Dolby Digital',
'THX',
'DLP',
);




$api_value = 5;
echo bitmap_decode( $info1, $api_value, 'Sell' ); // 0


$api_value = 35;
echo bitmap_decode( $info1, $api_value, 'Sell' ); // 1

And then we can do the opposite - encode the values without having to think about any non-binary numbers or anything like that:

function bitmap_encode( $items, $label_array ) {
$return = 0;
$label_array = array_flip( $label_array ); // swap the keys and values
foreach ( $items as $item ) {
$i = $label_array[ $item ]; // get the decimal key value for the item on the list
$i = 2**$i; // use 2 to the nth power to get the decimal bitmap value for the item
$return += $i; // add $i to the return value
}
return $return;
}


// set these flags as true
$flags = array( 'Display', 'Sell', 'THX' );
echo bitmap_encode( $flags, $info1 ); // 35

I know this does not precisely answer the OP question, but it's another approach to making a bitmask system in PHP.