I'd use XOR
(exclusive or) for this, because it's intended for this purpose, so using a dirty workaround with an array is not as easy to understand.
if (!(!empty($var1) && !empty($var2) && !empty($var3)) && (!empty($var1) ^ !empty($var2) ^ !empty($var3))) {
echo "Only one string is not empty\n";
}
And it's about 25% faster than the accepted answer.
$before = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
$var1 = 'Hello';
$var2 = '';
$var3 = '';
if (!(!empty($var1) && !empty($var2) && !empty($var3)) && (!empty($var1) ^ !empty($var2) ^ !empty($var3))) {
echo "Only one string is not empty\n";
}
$var4 = '';
$var5 = '';
$var6 = '';
if (!(!empty($var4) && !empty($var5) && !empty($var6)) && (!empty($var4) ^ !empty($var5) ^ !empty($var6))) {
echo "Only one string is not empty\n";
}
$var7 = 'Hello';
$var8 = 'World';
$var9 = '!';
if (!(!empty($var7) && !empty($var8) && !empty($var9)) && (!empty($var7) ^ !empty($var8) ^ !empty($var9))) {
echo "Only one string is not empty\n";
}
}
$after = microtime(true);
echo ($after-$before)/$i . " sec for XOR\n";
// 3.2943892478943E-6 sec for XOR
$before = microtime(true);
for ($i = 0; $i < 100000; ++$i) {
$var1 = 'Hello';
$var2 = '';
$var3 = '';
if (count(array_filter(array($var1, $var2, $var3))) == 1) {
echo "Only one string is not empty\n";
}
$var4 = '';
$var5 = '';
$var6 = '';
if (count(array_filter(array($var4, $var5, $var6))) == 1) {
echo "Only one string is not empty\n";
}
$var7 = 'Hello';
$var8 = 'World';
$var9 = '';
if (count(array_filter(array($var7, $var8, $var9))) == 1) {
echo "Only one string is not empty\n";
}
}
$after = microtime(true);
echo ($after-$before)/$i . " sec for Arrays\n";
// 4.3078589439392E-6 sec for Arrays
*I had to update the answer because the name "exclusive or" is somewhat misleading in context of more than two expressions. Of course all commenters are right, and exclusive or is a binary operation therefore resolving from left to right. 1 ^ 1 ^ 1 == 1
resolves to 0 ^ 1 == 1
and is therefore true
. Exclusive or does actually look for an odd number of trues.
I updated my answer with an easy-to-read workaround, but this definitely doesn't satisfy me and I have to admin that I resolved a huge misconception of boolean operators in my mind. The last time was a wrong assumption of AND
and OR
being resolved from left to right rather than first AND
then OR
.*