19

I find myself doing this kind of thing somewhat often:

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

With bitwise operators, you can use the &= and |= shorthand:

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

Given that bitwise operations on 1 and 0 are functionally equivalent to boolean operations on true and false, we can rely on type-casting and do something like this:

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

...but that's pretty ugly and defeats the purpose of using a shorthand assignment syntax, since we have to use another statement to get the type back to boolean.

What I'd really like to do is something like this:

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

...but &&= and ||= are not valid operators, obviously. So, my question is - is there some other sugary syntax or maybe an obscure core function that might serve as a stand-in? With variables as short as $foo, it's not a big deal to just use $foo = $foo && false syntax, but array elements with multiple dimensions, and/or object method calls can make the syntax quite lengthy.

FtDRbwLXw6
  • 27,774
  • 13
  • 70
  • 107
  • What is wrong with $foo = $foo && false;? Or is it just curiosity? – Dany Caissy Jul 09 '13 at 16:08
  • 2
    @DanyCaissy: I explained in the last paragraph. There's nothing *wrong* with it; it's just that that syntax is redundant, and can get very lengthy (e.g. `$some['big']['long']['variable'] = $some['big']['long']['variable'] && $some['other']['boolean'];`). – FtDRbwLXw6 Jul 09 '13 at 16:10
  • You may want to change your examples. Logically, these will always yield the same result = `$foo &= false;` and `$foo &&= false;` for `$foo = true`. So I'm failing to see the problem/goal. – Jason McCreary Jul 09 '13 at 16:19
  • 2
    @JasonMcCreary: It depends on your definition of "same." As my examples point out, the former yields `int(0)` and the latter yields `bool(false)`. So while `0 == false` because of implicit type-casting, `0 !== false`. – FtDRbwLXw6 Jul 09 '13 at 16:50
  • This is still relevent 7 years latter with PHP7/8 type enforcement checks. Very easy to accidentally convert from a bool to an int if you use short syntax. – evo_rob Apr 06 '21 at 11:26
  • Knowing `$mailsSent = (Swift_Mailer)$mailer->send($message)` is `false`, if mail not sent, I've been using `$mailsSent &= $mailer->send($message2)` consecutively. After a year of such usage it was the first time, that I had different number of recipients in first and second mail group. Today I found out two things. First if mails are successfully sent `send()` method returns the number of mails sent and not `true`. Second `&=` is a bitwise assignment operator, meaning `1 + 2 = 0`. Should've read the docs more thoroughly. Solved it with `(bool)$mailer->send($message)`. – s3c Sep 07 '21 at 12:43

3 Answers3

5

In a way you have answered your own question:

bitwise operations on 1 and 0 are functionally equivalent to boolean operations on true and false

Bearing in mind that PHP is a weakly typed language, so it is not necessary to typecast to and from strict boolean values as 1 and 0 are equivalent to true and false (except strict equality, see below).

Consider the following code, using your examples:

$foo = true;
$foo &= false;

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

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

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

// Output: Bitwise works!Boolean works!

Given PHP's implicit type juggling, falsy values, and with the exception of strict equaltiy, I'm hard pressed to see where such shorthand operations of &&= and ||= would not yield the same result as &= and |=. Especially when evaluating boolean values. It's likely why such shorthands don't exist in PHP.

Update

Some quick benchmarks prove these are indeed equivalent, except for truthy arrays/objects:

<?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)
// }
Jason McCreary
  • 71,546
  • 23
  • 135
  • 174
  • 1
    You're correct, but I was actually looking for a solution that didn't change the type (hence why my 3rd example was explicitly type-casting back into a `bool`). I have control over both the operands, and they're guaranteed to be `bool`s, so I'd much rather just use the longer syntax than potentially introduce errors into the code by returning "falsy" values instead of a strict `bool` like the interface has documented. – FtDRbwLXw6 Jul 09 '13 at 17:00
  • 1
    Fair. Even though PHP is a weakly typed, dynamic language, I support writing such explicit code. My answer is based on that fact that for boolean values (and most other simple types) bitwise operators are equivalent to boolean operators. But if you want to use such a shorthand, you have to give up strict equality checks (or compare to 0/1). In the end, I don't really see the point. Nonetheless, I wanted to provide an answer for future readers. – Jason McCreary Jul 09 '13 at 17:24
  • Keep in mind, you could always cast it before returning the value. Probably good practice anyway. – Jason McCreary Jul 09 '13 at 17:45
  • @JasonMcCreary No, boolean and bitwise operators are not equivalent, though their output is. The big difference is, that PHP does not even execute an expression for boolean operates if the outcome makes no difference. So `$res = sql_query() OR die();` is not equivalent to `$res = sql_query(); $res |= die();`. – Matteo B. Mar 25 '15 at 11:45
  • 1
    @Matmarbon, correct, in these comments I forgot a key qualifier - **functionally** equivalent. – Jason McCreary Mar 25 '15 at 12:57
  • Unfortunately with strong type checking that is no longer true @JasonMcCreary. `$result = true; $result &= somefun()` will change the type for $result from a `bool` to an `int`. I still see a usecase for a boolean assignment operator in php. In fact, that is the reaseon why I came here. – theking2 Apr 06 '22 at 11:58
1

As Jason mentioned, bitwise operators will work and it will not be necessary to convert the result back to boolean, as PHP will already handle their value as a boolean properly.

If you want an alternative that does not use bitwise operators, for the sake of readability or if you want strict equality, you can use this method :

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

Which means, you could change this :

$foo = $foo && false;

To this :

OrOp($foo, false);

It would also work with multiple conditions :

OrOp($foo, $condition1 && $condition2 && $condition3);
Dany Caissy
  • 3,176
  • 15
  • 21
  • 2
    While helpful, it seems the OP is looking for something native and aware they can write custom code. – Jason McCreary Jul 09 '13 at 16:22
  • 1
    I don't think there is something native that would do it for them, this is why I put this here. I'll remove my answer if I am proven wrong. While I'm sure OP could have came up with this method by himself, future readers that are less experienced might find it useful. – Dany Caissy Jul 09 '13 at 16:23
  • Did someone thing to post this to the PHP dev team? – theking2 Apr 06 '22 at 12:00
  • I did: [on github](https://github.com/php/php-src/issues/8312) – theking2 Apr 06 '22 at 12:09
1

Right, &&= and ||= operators are indeed missing in PHP because bitwise operators can not be used as a replacement (without casting).

Here is an example you would expect to return true but returns false:

$a = true;
$a &= 10; // => returns 0 (false) because 1 & 10 = 0

The missing &&= operator would return true because 1 && 10 = true

$a = true;
$a &&= 10; // => $a would be true