【问题标题】:Boolean assignment operators in PHPPHP中的布尔赋值运算符
【发布时间】:2013-07-07 08:12:08
【问题描述】:

我发现自己经常做这种事情:

$foo = true;
$foo = $foo && false; // bool(false)

使用位运算符,您可以使用&= 和|= 速记:

$foo = 1;
$foo &= 0; // int(0)

鉴于1 和0 上的按位运算在功能上等同于true 和false 上的布尔运算,我们可以依靠类型转换并执行以下操作:

$foo = true;
$foo &= false; // int(0)
$foo = (bool)$foo; // bool(false)

...但这很丑陋并且违背了使用速记赋值语法的目的,因为我们必须使用另一个语句来将类型恢复为布尔值。

我真正想做的是这样的:

$foo = true;
$foo &&= false; // bool(false)

...但是 &&= 和 ||= 显然不是有效的运算符。所以,我的问题是 - 是否有其他一些含糖的语法或者可能作为替代品的晦涩的核心功能?对于像 $foo 这样短的变量,只使用 $foo = $foo && false 语法没什么大不了的,但是具有多个维度的数组元素和/或对象方法调用会使语法变得很长。

【问题讨论】:

  • $foo = $foo && false; 有什么问题?还是只是好奇?
  • @DanyCaissy:我在最后一段中解释过。它没有任何错误;只是该语法是多余的,并且可能会变得非常冗长(例如$some['big']['long']['variable'] = $some['big']['long']['variable'] && $some['other']['boolean'];)。
  • 你可能想改变你的例子。从逻辑上讲,这些总是会产生相同的结果 = $foo &= false; 和 $foo &&= false; 对于$foo = true。所以我没有看到问题/目标。
  • @JasonMcCreary:这取决于您对“相同”的定义。正如我的例子所指出的,前者产生int(0),后者产生bool(false)。所以虽然0 == false 因为隐式类型转换,0 !== false.
  • 这仍然是 7 年后的 PHP7/8 类型强制检查。如果使用短语法,很容易意外地从 bool 转换为 int。

标签: php syntax boolean-logic syntactic-sugar


【解决方案1】:

在某种程度上你已经回答了你自己的问题:

对 1 和 0 的按位运算在功能上等同于对 true 和 false 的布尔运算

请记住,PHP 是一种弱类型语言,因此没有必要对严格的布尔值进行类型转换,因为1 和0 等同于true 和@ 987654327@(严格相等除外,见下文)。

使用您的示例考虑以下代码:

$foo = true;
$foo &= false;

if (!$foo) {
  echo 'Bitwise works!';
}

$bar = true;
$bar = $bar && false;

if (!$bar) {
  echo 'Boolean works!';
}

// Output: Bitwise works!Boolean works!

鉴于 PHP 的 implicit type juggling、falsy values 和 strict equaltiy 除外,我很难看到 &&= 和 ||= 的这种速记操作不会产生与 @987654331 相同的结果@ 和 |=。尤其是在评估布尔值时。这可能是 PHP 中不存在这种速记的原因。

更新

一些快速的基准测试证明这些确实是等价的,除了 truthy 数组/对象:

<?php
$values = array(false, 0, 0.0, "", "0", array(), 12, "string", array(1));

foreach ($values as $value) {
    $bit_test = true;
    $bit_test &= $value;

    $bool_test = true;
    $bool_test = $bool_test && false;
    if ($bit_test != $bool_test) {
        echo 'Difference for: ';
        var_dump($value);
    }
}

// Output:
// Difference for: array(1) {
//  [0]=>
//  int(1)
// }

【讨论】:

  • 你是对的,但我实际上是在寻找一个不改变类型的解决方案(因此我的第三个示例明确地将类型转换回bool)。我可以控制这两个操作数,并且保证它们是bools,所以我宁愿只使用更长的语法,也不愿通过返回“虚假”值而不是严格的@987654336 来潜在地将错误引入代码中@ 就像接口记录的那样。
  • 公平。尽管 PHP 是一种弱类型的动态语言,但我支持编写这样的显式代码。我的回答是基于这样一个事实,即对于布尔值(和大多数其他简单类型),按位运算符等效于布尔运算符。但是如果你想使用这样的简写,你必须放弃严格的相等检查(或与 0/1 比较)。最后,我真的不明白这一点。尽管如此,我还是想为未来的读者提供一个答案。
  • 请记住,您始终可以在返回值之前对其进行转换。无论如何,这可能是一种很好的做法。
  • @JasonMcCreary 不,布尔运算符和位运算符不等价,尽管它们的输出是等价的。最大的区别是,如果结果没有区别,PHP 甚至不会执行布尔运算的表达式。所以$res = sql_query() OR die(); 不等于$res = sql_query(); $res |= die();。
  • @Matmarbon,正确,在这些 cmets 中我忘记了一个关键限定符 - 功能上等效。
【解决方案2】:

正如 Jason 所提到的,按位运算符将起作用,并且没有必要将结果转换回布尔值,因为 PHP 已经将它们的值作为布尔值正确处理。

如果你想要一个不使用位运算符的替代方案,为了可读性或者如果你想要严格相等,你可以使用这个方法:

function OrOp(&$booleanVar, $conditions)
{
    $booleanVar = $booleanVar && $conditions;
    return $booleanVar;
}

也就是说,你可以改变这个:

$foo = $foo && false;

到这里:

OrOp($foo, false);

它也适用于多种条件:

OrOp($foo, $condition1 && $condition2 && $condition3);

【讨论】:

  • 虽然有帮助,但似乎 OP 正在寻找原生的东西,并且知道他们可以编写自定义代码。
  • 我不认为有本地的东西可以为他们做这件事,这就是我把它放在这里的原因。如果我被证明是错误的,我将删除我的答案。虽然我确信 OP 可以自己想出这种方法,但经验不足的未来读者可能会发现它很有用。
猜你喜欢
  • 2012-09-20
  • 1970-01-01
  • 2023-03-08
  • 2016-09-28
  • 2013-02-27
  • 2013-02-08
  • 2016-04-30
  • 2013-03-02
  • 1970-01-01
相关资源
最近更新 更多