25 Aug 2020

PHP ternary operator, elvis operator, null coalescing operator, and null safe operator

Ternary Operator

Ternary Operator (?:) it's an inline if-else statement.

Let's have a look at the following example:

$status = true;
$statusText = null;

if ($status === true) {
    $statusText = 'OK';   
} else {
    $statusText = 'Fail';
}

By using the ternary operator, we will be able to get rid of the entire if-else statement and replace it with a concise syntax:

$status = true;
$statusText = $status === true ? 'OK' : 'Fail';

Elvis Operator

Elvis operator (?:) returns its first operand if that operand evaluates to a true value.

Let's see how it works by looking at the following example:

$statusText = 'OK';

if ($statusText === "OK") {
	echo "OK";
} else {
	echo "Fail";
}

As you see, we've repeated the value of the $statusText twice, so instead of doing that, we could use the Elvis-operator as follows:

$statusText = 'OK';
echo $statusText ?: "Fail";

The variable needs to be defined before we using the elvis-operator, so the following code throws an error:

echo $statusText ?: "Fail";
PHP Notice:  Undefined variable: statusText in operators.php on line 2

We can solve it as follows:

if (isset($statusCode)) {
    echo $statusText ?: "Fail";
}

Null coalescing operator

This operator was introduced in PHP 7.0.

Null coalescing operator (??) works the exact same way as the elvis-operator, except it doesn't trigger a notice if the variable isn't defined or has a null value, hence it was named null coalescing:

echo $statusText ?? "Fail";

Empty values, false and 0 are considered to be NOT null, therefore they will be returned:

var_dump('' ?? "Second Value"); // string(0) ""
var_dump(false ?? "Second Value"); // bool(false)
var_dump(0 ?? "Second Value"); // int(0)

Let's try to use it on an undefined class property:

class Person { }

$person = new Person();
echo $person->name ?? 'No name'; // No name

It works well, but how about class properties?

Let's have a look at the following example:

interface Country { }

class Iraq implements Country 
{
    public string $name = 'Iraq';
}
	
class Person 
{
    public ?Country $country = null;
    
    public function __construct(?Country $country) {
        $this->country = $country;
    }
}
	
$person = new Person(nulll);

echo 'I am are from: ' . $person->country->name;
PHP Warning:  Attempt to read property "name" on null in ...

As you might have noticed, the country property on the Person class cen accept either a Country interface or a null value, but always expect it to have a Country object.

Let's see how to fix it in PHP < 8.0:

if ($country = $person->country) {
    echo 'I am from '. $country->name;
}

Null safe operator

This operator was introduced in PHP 8.0.

The null safe operator (?->) doesn't throw an exception if we try to access the name property on null:

echo $person->country?->name;

Basically, it's telling PHP to get the name propery if the object does exist, otherwise it should neglect it.