PHP位运算标志检测操作

3

// 你好,我想用位运算来排除一个标记,但是我不知道如何做: // 这里是标记(它们来自文件系统迭代器)

define('CURRENT_AS_FILEINFO', 0);
define('CURRENT_AS_SELF', 16);
define('CURRENT_AS_PATHNAME', 32);
define('CURRENT_MODE_MASK', 240);
define('KEY_AS_PATHNAME', 0);
define('KEY_AS_FILENAME', 256);
define('FOLLOW_SYMLINKS', 512);
define('KEY_MODE_MASK', 3840);
define('NEW_CURRENT_AND_KEY', 256);
define('SKIP_DOTS', 4096);
define('UNIX_PATHS', 8192);

用户可以潜在地设置任何组合的标志。 我需要检测是否设置了CURRENT_AS_SELF或CURRENT_AS_PATHNAME, 所以这是我的函数:

function containsPathnameOrSelfFlag($flags) {
    if ($flags & (CURRENT_AS_PATHNAME | CURRENT_AS_SELF)) {
        return true;
    }
    return false;
}

这里是一个测试套件:

var_dump(containsPathnameOrSelfFlag(CURRENT_MODE_MASK | CURRENT_AS_PATHNAME)); // true, ok
var_dump(containsPathnameOrSelfFlag(CURRENT_AS_FILEINFO)); // false, ok
var_dump(containsPathnameOrSelfFlag(CURRENT_MODE_MASK | CURRENT_AS_FILEINFO)); // true, but false was expected, because neither CURRENT_AS_SELF nor CURRENT_AS_SELF were set, so my function is wrong

能否使用位运算符使该函数通过第三个测试用例 (应返回false)?

我看到的问题是CURRENT_MODE_MASK的位与CURRENT_AS_SELF和CURRENT_AS_PATHNAME的位重叠:

0000000000010000 : CURRENT_AS_SELF 
0000000000100000 : CURRENT_AS_PATHNAME 
0000000011110000 : CURRENT_MODE_MASK 
0000000100000000 : KEY_AS_FILENAME
0000001000000000 : FOLLOW_SYMLINKS
0000111100000000 : KEY_MODE_MASK
0000000100000000 : NEW_CURRENT_AND_KEY
0001000000000000 : SKIP_DOTS
0010000000000000 : UNIX_PATHS

每当用户将 CURRENT_MODE_MASK 添加到标志中时,我的函数会认为 CURRENT_AS_SELF 和 CURRENT_AS_PATHNAME 也已经设置了,尽管这并不是实际情况。我不知道该如何解决这个问题。


CURRENT_MODE_MASK确实已经设置了CURRENT_AS_SELF和CURRENT_AS_PATHNAME标志...请将其更改为0000000011000000 - user254875486
谢谢你的答复,但标志位来自 FilesystemIterator 类,我不能改变它们,但也许我没有正确理解 CURRENT_MODE_MASK 的工作方式。 - ling
你必须以不同的方式检查标志。请参见我的答案 - PiTheNumber
我认为值得注意的是,KEY_MODE_MASK 的值实际上并不正确,因为 KEY_MODE_MASK & FOLLOW_SYMLINKS 返回一个真值结果,即使 FOLLOW_SYMLINKS 与任何键标志都无关。因此,使用 $any_key_flag_set = $fsiObj->getFlags() & $fsiObj::KEY_MODE_MASK; 将返回一个错误的结果。KEY_MODE_MASK 应该是3328(从其掩码中删除512),或者 FOLLOW_SYMLINKS 应该是16384,以将其从3840掩码中移除。 - Anthony
2个回答

3

面具旨在与当前值进行测试,而不是与新值进行或运算以生成新值。如果您想要测试某个标志的存在性或仅使用单个标志,则只需使用该标志即可。


感谢您的回答。 “掩码是用于与当前值进行测试的,而不是用于生成新值的或运算。”您的意思是如果用户像这样构建FilesystemIterator,那么他就是错误的吗? $o = new FilesystemIterator(DIR, FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::CURRENT_MODE_MASK);如果是这样,那么我的问题就不应该被发布,我的问题已经解决了(或者至少不是一个真正的用例)。 - ling
1
正确。应该使用掩码从 getFlags() 中隔离出特定的标志,而不是为新迭代器设置标志。 - Ignacio Vazquez-Abrams
感谢您提供的准确信息,这个标志的有用信息很难找到。PHP文档只是说:“Masks FilesystemIterator :: current()”,这对某些人可能容易理解(但不是我),而我唯一找到的“文档”在这里http:// chat.stackoverflow.com/transcript/11/2011/3/20/8-21,这也让我感到困惑。现在我想我懂了。谢谢。 - ling

1
如果您不希望 CURRENT_MODE_MASKCURRENT_AS_SELFCURRENT_AS_PATHNAME 重叠,只需确保它们不共享一个被设置为1的公共位。 例如,您可以将 CURRENT_MODE_MASK 设置为64或192以适应当前值。

谢谢您的回答,但我无法更改CURRENT_MODE_MASK的值,它来自FilesystemIterator类:http://www.php.net/manual/en/class.filesystemiterator.php。我不确定如何使用CURRENT_MODE_MASK,也许它不应该与CURRENT_AS_SELF和CURRENT_AS_PATHNAME一起使用,但当用户使用CURRENT_MODE_MASK和(CURRENT_AS_SELF或CURRENT_AS_PATHNAME)标志设置标志时不会抛出错误。 - ling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接