如何在php中实现位掩码?


76

我不确定位掩码是否正确。让我解释:

在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页面获得术语bitmask

无论如何,我已经实现了一个称为SIMPLE的方法ls,该方法返回目录的内容。

此函数需要3个参数...($ include_hidden = false,$ return_absolute = 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 );

等等...

我应该如何测试已调用的标志呢?

Answers:


149

实际上,这很简单。首先,用一些代码演示如何实现。如果您对该代码的功能或工作原理一无所知,请随时在注释中提出其他问题:

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);

演示版


因为标志是整数,所以在32位平台上最多可以定义32个标志。在64位平台上,它是64。也可以将标志定义为字符串,在这种情况下,可用标志的数量或多或少是无限的(当然,在系统资源的范围内)。这是二进制形式的工作原理(为简单起见,缩减为8位整数)。

FLAG_1
Dec:    1
Binary: 00000001

FLAG_2
Dec:    2
Binary: 00000010

FLAG_3
Dec:    4
Binary: 00000100

// And so on...

当您组合标志以将它们传递给函数时,可以将它们或在一起。让我们看看当我们通过时会发生什么FLAG_1 | FLAG_3

  00000001
| 00000100
= 00000101

当您想查看设置了哪些标志时,可以将标志与位掩码相加。因此,让我们接受上面的结果,看看是否FLAG_3已设置:

  00000101
& 00000100
= 00000100

...我们返回标志的值,这是一个非零整数-但是如果我们看到是否FLAG_2已设置:

  00000101
& 00000010
= 00000000

...我们得到零。这意味着您可以在检查值是否通过时简单地将AND操作的结果评估为布尔值。


9
因此,基本的按位操作是:$flags & FLAG_1-检查是否$flags | FLAG_1设置了FLAG_1,$flags & ~FLAG_1-设置了FLAG_1,-未设置FLAG_1,~$flags-反转了标志
Konstantin

7
我不了解PHP,并且很可能永远也不会学习它,但我很高兴我偶然发现了这个问题-您的解释可以帮助任何人以任何语言实现位图:)
Chris Cirefice 2013年

6
我建议将2位小数的幂定义为1的按位移位运算。 define('FLAG_1', 1<<0); define('FLAG_2', 1<<2); define('FLAG_3', 1<<3); define('FLAG_4', 1<<4); 这通常是在C语言中完成的
AmitP 2014年

6
@AmitP在PHP中,这种方法存在两个(次要)问题。1)当前const关键字不支持表达式,即使结果为常数(即const FLAG_1 = 1 << 0;是解析错误)-显然这不是问题define()2)在C中,常数表达式const int FLAG_1 = 1 << 0;将在编译时被解析,并且实际已编译值将是表达式的结果,而在PHP中,每次都会对其进行微观性能评估。这些问题都不是避免您建议使用更具可读性的版本的充分理由。
DaveRandom 2014年

1
@Benjamin与这个问题无关,但是您可以使用const scalar exprs来做一件有用的事情:const IS_WINDOWS = \PHP_OS & "\xDF\xDF\xDF" === 'WIN';相当于非常常见的stripos(\PHP_OS, 'WIN') === 0成语的编译时。碰巧的是,这是毫无意义的(PHP_OS当前始终 'WINNT'在所有版本的Windows上使用),但我想它是面向未来的……
DaveRandom

17
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..

然后,您可以检查ls函数中的各个标志:

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

7
您知道使用十六进制数字代替整数的优势吗?只是好奇:)
AlexMorley-Finch 2014年

@ AlexMorley-Finch似乎纯属偏爱,使用小数或十六进制似乎都根本没有改变执行时间
Brian Leishman

2

其他人提出了很好的建议,但是如今,传递关联数组而不是位掩码更为常见。它更具可读性,并允许您传递其他变量,而不仅仅是true / false值。像这样:

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

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

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

3
我也曾经这样做过,但是其他同伴抱怨他们的IDE中没有“类型提示”,没有适当的文档注释,并且当未传递必需的参数时,该函数也不会引发错误。理想情况下,“命名参数”将解决所有这些问题,如果它们存在于php中
Timo Huovinen 2015年

嗨@TimoHuovinen-感谢您的评论。可以很容易地添加概述选项和默认值的文档注释,并在需要时抛出异常,并将参数默认为允许类型提示的数组。那对你有用吗?
西蒙东

哦,我懂了。Symfony OptionsResolver类进一步提供了更多功能。凉。
西蒙东

很容易添加概述选项和默认值的文档注释”是的,您可以像twig一样添加它们 但这仍然是一种解决方法。” ,并将参数默认设置为允许类型提示的数组“您将如何执行此操作?我的意思是IDE类型提示和代码完成,其中编辑器告诉您函数可以接受哪些参数。(请记住,我也希望使用数组作为选项,只是我需要弄清楚如何使同伴开心)
Timo Huovinen 2015年

这种方法的问题是,您最终将获得大量的if else语句
numediaweb
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.