PHP中的“Elvis运算符”(?:运算符)

370

今天我在一些 PHP 代码中看到了这个:

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

我对这里使用的 ?: 运算符不熟悉。它看起来像是一个三目运算符,但如果谓词为真,则省略了要评估的表达式。这是什么意思?


7
我不知道“埃尔维斯”这个名字。+1。 - Gobinda Nandi
7个回答

736

如果左操作数为真值,则返回左操作数的值;否则返回右操作数的值。

在伪代码中,

foo = bar ?: baz;

大致解决为
foo = bar ? bar : baz;

或者

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

与之不同的是,bar只会被评估一次。

你还可以使用这个方法来对foo进行“自检”,就像你发布的代码示例中所演示的那样:

foo = foo ?: bar;

这将在foo为空或为假值时将bar赋给foo,否则将保持foo不变。
一些更多的例子:
<?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'
?>

顺便说一下,它被称为Elvis运算符

Elvis operator


18
请确保括号中的变量存在,否则会引发错误。PHP不会假设它具有空值或任何其他值。就这样说。 - DanMan
4
为什么不直接使用 || 呢?像这样: blah || 'default' - Noitidart
32
因为在JS中,它会返回最左边的真值操作数,而在PHP中,||运算符始终返回一个布尔值。 - ksadowski
2
对于任何想知道的人,空字符串是假值,因此 var_dump('' ?: 'foo'); 将是 foo - AlbinoDrought
通常你会遇到这样的代码 __construct(MyClient $client = null) { $client = $client ?: new MyClient; }。当 null 是唯一的“falsey”选项时,最好使用 $client ??= new MyClient;,它大致相当于 if ($client === null) { $client = new MyClient; } - s3c

70

请参阅文档

自PHP 5.3以来,三元运算符的中间部分可以省略。表达式expr1 ?: expr3如果expr1计算结果为TRUE,则返回expr1,否则返回expr3


2
说实话,文档是正确的。expr2 发生了什么事情,它只是消失了,没有被评估。$this->expensiveComputation() ?: "nope" 不等同于 $this->expensiveComputation() ? $this->expensiveComputation() : "nope" - expr1 只被评估一次。 - Piskvor left the building

30

小心处理数组。我们必须在 ? 后面编写一个检查变量,因为:

  $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

更新

根据 RFC,在 PHP 7 中,使用 空值合并运算符 可以实现相同的功能,例如:

$param1 = $params['param1'] ?? null;
// Equivalent to:  $param1 = isset($params['param1']) ? $params['param1'] : null;

所以 null coalesce 和 Elvis 是一样的吗? - Nabeel Khan
9
@NabeelKhan 不行!在我看来,这让 Elvis运算符 在PHP中有点无用。Elvis运算符评估一个表达式,如果它是真的,就返回它,否则返回最后一部分。由于PHP弱类型,很多东西都可能是真或假,而且很可能不是你想要的。例如:如果您想为一个变量设置默认值,如果它没有定义,使用 Elvis运算符,PHP会说0未定义,但是您可能想要0...这就是为什么 PHP 7将引入 Null Coalesce运算符的原因,它将严格测试变量是否为null,所以PHP会说0未定义。 - Gregoire D.
可以用@$arr[$key]的语法来代替isset($arr[$key])。 - Fusca Software
7
根据我的经验,像这样使用错误抑制并不是一个好主意。 - TeeHays

18

Elvis运算符:

?:是Elvis运算符。这是一个二元运算符,它执行以下操作:

?:左侧的值强制转换为布尔值,并检查是否为true。如果为true,则返回左侧表达式,否则返回右侧表达式。

示例:

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

何时使用:

Elvis运算符基本上是三元运算符的一种特定情况的简写语法,即:

$testedVar ? $testedVar : $otherVar;
Elvis运算符将通过以下方式使语法更加简洁:
$testedVar ?: $otherVar;

请注意,空数组也会被视为false。var_dump([] ?: 'Expression not true');将返回"Expression not true"。因此,Elvis运算符有点像检查empty(),而null合并运算符(??)更像是测试isset() - BadHorsie

10

另一个重要的考虑因素是:Elvis操作符会破坏Zend Opcache的标记化过程。我通过艰难的方式发现了这一点!虽然这个问题可能已经在以后的版本中得到解决,但我可以确认这个问题存在于PHP 5.5.38(内置Zend Opcache v7.0.6-dev)中。

如果您发现您的一些文件“拒绝”被缓存在Zend Opcache中,这可能是其中之一的原因...希望这可以帮助您!


4

是的,这在PHP 5.3中是新功能。它返回测试表达式的值,如果被评估为TRUE,则返回该值,否则返回替代值。


0

我认为目的是条件执行:

$a ?: func(); 

如果$a的值为FALSE,那么func()中的结果将不会被执行。它可以被用作一个简写。

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

这个赋值语句是可选的 $a = $a ?: func() 就像:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接