Thursday, 25 June 2015

PHP 7: null coalescing operator

G'day:
There's not much to say on this one, but I'll go through motions anyhow. First things first, I'm dead pleased they've gone for ?? rather than ?:, as I don't have to listen to people say "elvis operator" as I do in the CFML world. "Small things", I know.



Right, so the null coalescing operator simply returns the first of its operands that is not null, going left to right (something you probably already knew, but hey). This is handy for defaulting potentially un-set variables, say for example a param passed on the URL:

// default.php

$id = $_GET['id'] ?? 0;

echo "ID: $id";

So if we run this without passing an id parameter on the URL, $id is set to 0, otherwise it's set to whatever you pass. Handy.

There's not much else to say about it. Here's some examples of it being used for various "null" situations, and some not null ones too:


// variations.php

function returnsFalse() {
    return false;
}

function returnsNull($message='') {
    if (strlen($message)) echo $message;
    return null;
}

function defaulter(){
    echo 'DEFAULTER CALLED<br>';
    return 'default';
}

echo('<h4>defaulting null</h4>');
$result = null ?? defaulter('null');
echo "Result: [$result]<hr>";;

echo('<h4>defaulting false</h4>');
$result = false ?? defaulter('false');
echo "Result: [$result]<hr>";

echo('<h4>defaulting empty string</h4>');
$result = '' ?? defaulter('');
echo "Result: [$result]<hr>";

echo '<h4>defaulting returnsFalse()</h4>';
$result = returnsFalse() ?? defaulter('returnsFalse()');
echo "Result: [$result]<hr>";

echo('<h4>defaulting returnsNull()</h4>');
$result = returnsNull() ?? defaulter('returnsNull()');
echo "Result: [$result]<hr>";

echo('<h4>example of chaining</h4>');
$result = returnsNull('first call to returnsNull()<br>') ?? returnsNull('second call to returnsNull()<br>') ?? returnsNull('third call to returnsNull()<br>') ?? defaulter('chained');
echo "Result: [$result]<hr>";

And the output:

defaulting null

DEFAULTER CALLED
Result: [default]


defaulting false

Result: []

defaulting empty string

Result: []

defaulting returnsFalse()

Result: []

defaulting returnsNull()

DEFAULTER CALLED
Result: [default]


example of chaining

first call to returnsNull()
second call to returnsNull()
third call to returnsNull()

DEFAULTER CALLED
Result: [default]



This demonstrates a few things:
  • it really is only interested in whether the operands are null. Not false or 0 or empty string or what have you.
  • It's short-circuited so the second operand is not evaluated at all if the first operand is not-null already. Note how the defaulter() function is only called if it needs to be.
  • Calls to it can be chained.

That's about it!

--
Adam