364

I saw this today in some PHP code:

$items = $items ?: $this->_handle->result('next', $this->_result, $this);

I'm not familiar with the ?: operator being used here. It looks like a ternary operator, but the expression to evaluate to if the predicate is true has been omitted. What does it mean?

user4157124
  • 2,809
  • 13
  • 27
  • 42
alpha_juno
  • 3,643
  • 2
  • 16
  • 6

7 Answers7

733

It evaluates to the left operand if the left operand is truthy, and the right operand otherwise.

In pseudocode,

foo = bar ?: baz;

roughly resolves to

foo = bar ? bar : baz;

or

if (bar) {
    foo = bar;
} else {
    foo = baz;
}

with the difference that bar will only be evaluated once.

You can also use this to do a "self-check" of foo as demonstrated in the code example you posted:

foo = foo ?: bar;

This will assign bar to foo if foo is null or falsey, else it will leave foo unchanged.

Some more examples:

<?php
    var_dump(5 ?: 0); // 5
    var_dump(false ?: 0); // 0
    var_dump(null ?: 'foo'); // 'foo'
    var_dump(true ?: 123); // true
    var_dump('rock' ?: 'roll'); // 'rock'
    var_dump('' ?: 'roll'); //  'roll'
    var_dump('0' ?: 'roll'); //  'roll'
    var_dump('42' ?: 'roll'); //  '42'
?>

By the way, it's called the Elvis operator.

Elvis operator

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 18
    Make sure that the variable in the parenthesis exists though, or you're going to raise an error. PHP will not just assume it having a value of `null` or anything. Just sayin' – DanMan Aug 13 '15 at 11:10
  • 4
    Why not just use a `||`. So `blah || 'default'`? – Noitidart Apr 10 '18 at 13:45
  • 32
    @Noitidart Because, unlike in JS where it returns the leftmost truthy operand, in PHP the `||` operator always returns a boolean. – ksadowski Jun 19 '18 at 15:28
  • 2
    For anyone wondering, an empty string is falsey so `var_dump('' ?: 'foo');` would be `foo` – AlbinoDrought Mar 11 '19 at 18:40
  • Often you have something like `__construct(MyClient $client = null) { $client = $client ?: new MyClient; }`. When `null` is the only "falsey" option for variable, you're better of with `$client ??= new MyClient;`, which roughly translates to `if ($client === null) { $client = new MyClient; }`. – s3c Sep 12 '22 at 12:22
70

See the docs:

Since PHP 5.3, it is possible to leave out the middle part of the ternary operator. Expression expr1 ?: expr3 returns expr1 if expr1 evaluates to TRUE, and expr3 otherwise.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Yacoby
  • 54,544
  • 15
  • 116
  • 120
  • 2
    TBH, the docs are correct. What happened to `expr2` is that it just disappeared, and isn't evaluated. `$this->expensiveComputation() ?: "nope"` is not identical to `$this->expensiveComputation() ? $this->expensiveComputation() : "nope"` - expr1 is only evaluated once. – Piskvor left the building Nov 15 '19 at 13:19
30

Be careful with arrays. We must write a checking variable after ?, because:

  $params = ['param1' => 'value1',
             'param2' => 'value2',
             'param3' => 'value3',];

  $param1 = isset($params['param1'])?:null;
  $param2 = !empty($params['param2'])?:null;
  $param3 = $params['param3']?:null; // get E_NOTICE, if $params['param3'] eq false

  var_dump($param1,$param2,$param3);
  true // would like to expect `value1`
  true // would like to expect `value2`
  param3 // properly, but problem above

Updated

From RFC. In PHP 7 the operator Null Coalesce Operator will do it, for example:

$param1 = $params['param1'] ?? null;
// Equivalent to:  $param1 = isset($params['param1']) ? $params['param1'] : null;
Martin
  • 22,212
  • 11
  • 70
  • 132
voodoo417
  • 11,861
  • 3
  • 36
  • 40
  • so null coalesce and elvis are same? – Nabeel Khan Apr 11 '16 at 03:59
  • 9
    @NabeelKhan No! And that's make the Elvis operator kinda useless in PHP imo. The Elvis operator evaluate an expression and if it's true, it returns it else it return the last part. As PHP is low typed a lot of things will be true, or false, and most likely things won't be what you want. I.e: You want to set a default value to a variable if it is not defined, using the Elvis operator PHP will says that 0 is not defined, but you might want that 0... That's why PHP 7 will get the Null Coalesce operator, It will strictly test your variable against null, so PHP will says that 0 is not undefined. – Gregoire D. Apr 20 '16 at 10:01
  • instead of isset($arr[$key]) someone can just use the @$arr[$key] syntax – Fusca Software Nov 16 '17 at 21:55
  • 7
    @FuscaSoftware : Using error suppression like this isn't a good idea in my experience. – TeeHays Aug 07 '18 at 11:15
17

Elvis operator:

?: is the Elvis operator. This is a binary operator which does the following:

Coerces the value left of ?: to a boolean and checks if it is true. If true it will return the expression on the left side, if false it will return the expression on the right side.

Example:

var_dump(0 ?: "Expression not true");     // expression returns: Expression not true
var_dump("" ?: "Expression not true");    // expression returns: Expression not true
var_dump("hi" ?: "Expression not true");  // expression returns string hi
var_dump(null ?: "Expression not true");  // expression returns: Expression not true
var_dump(56 ?: "Expression not true");    // expression return int 56

When to use:

The Elvis operator is basically shorthand syntax for a specific case of the ternary operator which is:

$testedVar ? $testedVar : $otherVar;

The Elvis operator will make the syntax more consise in the following manner:

$testedVar ?: $otherVar;
kaznovac
  • 1,303
  • 15
  • 23
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
  • Note that an empty array also evaluates to false. `var_dump([] ?: 'Expression not true');` gives you "Expression not true". Therefore, the elvis operator is a bit like checking for `empty()` whereas the null coalesce operator (`??`) is more like testing `isset()`. – BadHorsie Mar 04 '22 at 16:40
10

Another important consideration: The Elvis Operator breaks the Zend Opcache tokenization process. I found this the hard way! While this may have been fixed in later versions, I can confirm this problem exists in PHP 5.5.38 (with in-built Zend Opcache v7.0.6-dev).

If you find that some of your files 'refuse' to be cached in Zend Opcache, this may be one of the reasons... Hope this helps!

Prasad Paradkar
  • 126
  • 1
  • 4
4

Yes, this is new in PHP 5.3. It returns either the value of the test expression if it is evaluated as TRUE, or the alternative value if it is evaluated as FALSE.

Atli
  • 7,855
  • 2
  • 30
  • 43
0

i think the purpose is conditional execution:

$a ?: func(); 

results in func() will only be executed if $a has a value that would resolve to FALSE. it may be used used as a short for

if(!$a){
    func();
}

thre assignment is optional $a = $a ?: func() is like:

if(!$a){
    $a = func();
}
ohjay
  • 11
  • 2