PHP三元运算符vs null合并运算符

时间:2016-01-02 22:23:40

标签: php php-7 ternary-operator null-coalescing-operator

有人可以解释PHP中三元运算符速记(?:)和空合并运算符(??)之间的差异吗?

他们什么时候表现不同,以同样的方式(如果发生这种情况)?

$a ?: $b

VS

$a ?? $b

13 个答案:

答案 0 :(得分:239)

当你的第一个参数为null时,它们基本相同,只是当你有一个未定义的变量时,空合并将不会输出E_NOTICEPHP 7.0 migration docs可以这样说:

  

空合并运算符(??)已添加为语法糖   对于需要使用三元组的常见情况   isset()函数。它返回第一个操作数(如果存在且不为NULL);   否则它返回第二个操作数。

以下是一些示例代码来说明这一点:

<?php

$a = null;

print $a ?? 'b';
print "\n";

print $a ?: 'b';
print "\n";

print $c ?? 'a';
print "\n";

print $c ?: 'a';
print "\n";

$b = array('a' => null);

print $b['a'] ?? 'd';
print "\n";

print $b['a'] ?: 'd';
print "\n";

print $b['c'] ?? 'e';
print "\n";

print $b['c'] ?: 'e';
print "\n";

它的输出:

b
b
a

Notice: Undefined variable: c in /in/apAIb on line 14
a
d
d
e

Notice: Undefined index: c in /in/apAIb on line 33
e

具有通知的行是我使用简写三元运算符而不是空合并运算符的行。但是,即使有通知,PHP也会给出相同的响应。

执行代码:https://3v4l.org/McavC

当然,这总是假设第一个参数是null。一旦它不再为null,那么你最终会产生差异,??运算符将始终返回第一个参数,而?:简写只有在第一个参数是真的时才会返回,并且这取决于{ {3}}

所以:

$a = false ?? 'f';
$b = false ?: 'g';
然后

$a等于false$b等于'g'

答案 1 :(得分:61)

如果您使用这样的快捷方式三元运算符,如果未设置$_GET['username'],则会发出通知:

$val = $_GET['username'] ?: 'default';

所以你必须做这样的事情:

$val = isset($_GET['username']) ? $_GET['username'] : 'default';

null合并运算符等同于上述语句,如果未设置$_GET['username']null,则会返回'default':

$val = $_GET['username'] ?? 'default';

请注意不检查真实性。它仅检查它是否已设置且不为空。

您也可以这样做,并且会返回第一个已定义的(设置而不是null)值:

$val = $input1 ?? $input2 ?? $input3 ?? 'default';

现在这是一个合适的合并算子。

答案 2 :(得分:38)

主要区别在于

  1. 三元运算符表达式expr1 ?: expr3如果expr1评估为expr1则返回TRUE (expr1) ?? (expr2)但另一方面空合并运算符表达式expr1 如果expr1 NULL

  2. ,评估结果为expr1 ?: expr3
  3. <强>三元 如果是左侧,话务员 (expr1)会发出通知 值(expr1) ?? (expr2)不存在但另一方面空的合并运算符 (expr1)特别是,如果左侧值isset()不发出通知,则不会发出通知 不存在,就像((true ? 'true' : false) ? 't' : 'f'); 一样。

  4. TernaryOperator 是左关联的

    ($a ?? ($b ?? $c));
    

    空合并运算符是右关联

    (?:)
  5. 现在让我们解释一下示例之间的区别:

    三元运算符 $x=''; $value=($x)?:'default'; var_dump($value); // The above is identical to this if/else statement if($x){ $value=$x; } else{ $value='default'; } var_dump($value);

    (??)

    空合并运算符 $value=($x)??'default'; var_dump($value); // The above is identical to this if/else statement if(isset($x)){ $value=$x; } else{ $value='default'; } var_dump($value);

    '??'

    下面是解释?:dataframe

    之间差异和相似性的表格

    enter image description here

      

    特别注意:null合并运算符和三元运算符是一个   表达式,并且它不会评估变量,而是评估变量   表达的结果。知道您是否愿意这一点非常重要   通过引用返回变量。声明返回$ foo ?? $酒吧;和   返回$ var == 42? $ a:$ b;在按引用返回的功能中   因此不起作用并发出警告。

答案 3 :(得分:33)

在php交互模式(终端上的php -a)上运行以下内容。每行的注释显示结果。

var_dump (false ?? 'value2');   # bool(false)
var_dump (true  ?? 'value2');   # bool(true)
var_dump (null  ?? 'value2');   # string(6) "value2"
var_dump (''    ?? 'value2');   # string(0) ""
var_dump (0     ?? 'value2');   # int(0)

var_dump (false ?: 'value2');   # string(6) "value2"
var_dump (true  ?: 'value2');   # bool(true)
var_dump (null  ?: 'value2');   # string(6) "value2"
var_dump (''    ?: 'value2');   # string(6) "value2"
var_dump (0     ?: 'value2');   # string(6) "value2"

所以这是我的解释:

1. Null Coalescing Operator - ??

  • ??就像一个“门”,只允许NULL通过
  • 所以, 它始终会返回第一个参数 ,除非 第一个参数恰好是NULL
  • 这意味着??( !isset() || is_null() )
  • 相同

2。三元运算符 - ?:

  • ?:就像一个让 anything falsy 通过的大门 - 包括NULL
  • 0empty stringNULLfalse!isset()empty() ......任何有气味的东西
  • 就像经典的三元运算符一样:echo ($x ? $x : false)
  • 注意:?:会将PHP NOTICE投放到未定义的(unset!isset())变量上

3。所以医生,我什么时候使用???: ..

  • 我只是在开玩笑 - 我不是医生,这只是一种解释
  • 我会在{时间}使用?:
    • 执行empty($x)检查
    • !empty($x) ? $x : $y等经典三元操作可以缩短为$x ?: $y
    • if(!$x) { fn($x); } else { fn($y); }可缩短为fn(($x ?: $y))
  • 我会在{时间}使用??
    • 我想进行!isset() || is_null()检查
    • 例如检查对象是否存在 - $object = $object ?? new objClassName();

4。堆叠操作员......

  1. 可以堆叠三元运算符 ...

    echo 0 ?: 1 ?: 2 ?: 3; //1
    echo 1 ?: 0 ?: 3 ?: 2; //1
    echo 2 ?: 1 ?: 0 ?: 3; //2
    echo 3 ?: 2 ?: 1 ?: 0; //3
    
    echo 0 ?: 1 ?: 2 ?: 3; //1
    echo 0 ?: 0 ?: 2 ?: 3; //2
    echo 0 ?: 0 ?: 0 ?: 3; //3
    

    Source & credit for this code

    这基本上是一个序列:

    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
    
  2. 可以堆叠Null Coalese运算符 ...

    $v = $x ?? $y ?? $z; 
    

    这是一系列:

    if(!isset($x) || is_null($x) ) {} 
    else if(!isset($y) || is_null($y) ) {}
    else {}
    
  3. 使用堆叠,我可以缩短它:

    if(!isset($_GET['name'])){
       if(isset($user_name) && !empty($user_name)){
          $name = $user_name;
       }else {
          $name = 'anonymous';
       }
    } else { 
       $name = $_GET['name'];
    }
    

    对此:

    $name = $_GET['name'] ?? $user_name ?: 'anonymous';
    

    很酷,对吗? : - )

答案 4 :(得分:12)

在动态数据处理方面,它们的行为都不同。

如果变量为空(&#39;&#39;),则空值合并会将变量视为真,但速记三元运算符不会被取消。这是值得考虑的事情。

jQuery(document.body).on('click', '.page', function() { 
    var randomClass = 3;
    var randomNumber = Math.round(Math.random() * (randomClass - 1)) + 1;
    jQuery(this).addClass("activated").addClass('scaled-' + randomNumber);

    var wrapper_scrollTop = $("#wrapper").scrollTop(); //gets amount scrolled
    var half_wrapper = $("#wrapper").height()*(0.5); //50% of wrapper height
    jQuery(this).css("top",half_wrapper+wrapper_scrollTop);

    jQuery(document.body).on('click', '.activated', function() { 
        jQuery(this).removeClass("activated scaled-1 scaled-2 scaled-3");
        jQuery(this).css("top","") //returns top to original value specified in css
    });
});

输出:

$a = NULL;
$c = '';

print $a ?? '1b';
print "\n";

print $a ?: '2b';
print "\n";

print $c ?? '1d';
print "\n";

print $c ?: '2d';
print "\n";

print $e ?? '1f';
print "\n";

print $e ?: '2f';

链接:https://3v4l.org/ZBAa1

答案 5 :(得分:9)

两者都是较长表达式的简写。

?:$a ? $a : $b的缩写。如果$ a的值为 TRUE ,则该表达式的值为$ a。

??isset($a) ? $a : $b的缩写。如果设置了$ a且不为null,则该表达式的计算结果为$ a。

当$ a未定义或为空时,它们的用例重叠。 $ a未定义时,??不会产生E_NOTICE,但是结果是相同的。 $ a为null时,结果相同。

答案 6 :(得分:3)

向下滚动this链接并查看该部分,它会为您提供一个比较示例,如下所示:

<?php
/** Fetches the value of $_GET['user'] and returns 'nobody' if it does not exist. **/
$username = $_GET['user'] ?? 'nobody';
/** This is equivalent to: **/
$username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

/** Coalescing can be chained: this will return the first defined value out of $_GET['user'], $_POST['user'], and 'nobody'. **/
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
?>

但是,不建议将操作符链接起来,因为稍后在阅读时会更难理解代码。

  

对于需要与isset()一起使用三元组的常见情况,添加了空合并运算符(??)作为语法糖。它返回第一个操作数(如果存在且不为NULL);否则它返回第二个操作数。

基本上,使用合并运算符会使其自动检查null,而不像三元运算符。

答案 7 :(得分:3)

其他答案更深入,并给出了很好的解释。对于那些寻求快速解答的人,

JSONAPISerializer$a ?: 'fallback'

同时

$a ? $a : 'fallback'$a ?? 'fallback'


主要区别在于左操作符为:

  • 一个不为空的虚假值($a = isset($a) ? $a : 'fallback'0''false,...)
  • 未定义的变量

答案 8 :(得分:2)

使用???:似乎有利有弊。使用?:的专业人员是它评估false和null以及&#34;&#34;相同。如果前面的参数为null,它会报告E_NOTICE。使用??,pro是没有E_NOTICE,但是con是它不评估false而null是相同的。根据我的经验,我看到人们开始使用null和false互换,但随后他们最终会修改他们的代码以使用null或false,但不能同时使用。另一种方法是创建更精细的三元条件:(isset($something) or !$something) ? $something : $something_else

以下是使用null和false的??运算符的区别示例:

$false = null;
$var = $false ?? "true";
echo $var . "---<br>";//returns: true---

$false = false;
$var = $false ?? "true";
echo $var . "---<br>"; //returns: ---

然而,通过详细说明三元运算符,我们可以制作一个假的或空的字符串&#34;&#34;如果它没有抛出e_notice就像是一个null:

$false = null;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = false;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = "";
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: ---

$false = true;
$var = (isset($false) or !$false) ? $false : "true";
echo $var . "---<br>";//returns: 1---

就个人而言,我认为如果未来的PHP版本包括另一个新的运算符:?取代上述语法,那将是非常好的。即: // $var = $false :? "true";该语法将评估null,false和&#34;&#34;同样地,不要抛出E_NOTICE ......

答案 9 :(得分:2)

对于初学者:

空合并运算符(??)

null值和未定义(变量/数组索引/对象属性)之外的所有内容都是正确的

例如:

$array = [];
$object = new stdClass();

var_export (false ?? 'second');                           # false
var_export (true  ?? 'second');                           # true
var_export (null  ?? 'second');                           # 'second'
var_export (''    ?? 'second');                           # ""
var_export ('some text'    ?? 'second');                  # "some text"
var_export (0     ?? 'second');                           # 0
var_export ($undefinedVarible ?? 'second');               # "second"
var_export ($array['undefined_index'] ?? 'second');       # "second"
var_export ($object->undefinedAttribute ?? 'second');     # "second"

这基本上是检查变量(数组索引,对象属性等)是否存在而不是null。类似于isset函数

三元运算符速记(?:)

所有虚假的东西(falsenull0,空字符串)都是假的,但是如果它是未定义的,它也是假的,但是Notice会是假的扔

ex

$array = [];
$object = new stdClass();

var_export (false ?: 'second');                           # "second"
var_export (true  ?: 'second');                           # true
var_export (null  ?: 'second');                           # "second"
var_export (''    ?: 'second');                           # "second"
var_export ('some text'    ?? 'second');                  # "some text"
var_export (0     ?: 'second');                           # "second"
var_export ($undefinedVarible ?: 'second');               # "second" Notice: Undefined variable: ..
var_export ($array['undefined_index'] ?: 'second');       # "second" Notice: Undefined index: ..
var_export ($object->undefinedAttribute ?: 'second');     # "Notice: Undefined index: ..

希望这会有所帮助

答案 10 :(得分:1)

class a
{
    public $a = 'aaa';
}

$a = new a();

echo $a->a;  // Writes 'aaa'
echo $a->b;  // Notice: Undefined property: a::$b

echo $a->a ?? '$a->a does not exists';  // Writes 'aaa'

// Does not throw an error although $a->b does not exist.
echo $a->b ?? '$a->b does not exist.';  // Writes $a->b does not exist.

// Does not throw an error although $a->b and also $a->b->c does not exist.
echo $a->b->c ?? '$a->b->c does not exist.';  // Writes $a->b->c does not exist.

答案 11 :(得分:0)

Null Coalescing operator只执行两项任务:检查whether the variable is setwhether it is null。看看下面的例子:

<?php
# case 1:
$greeting = 'Hola';
echo $greeting ?? 'Hi There'; # outputs: 'Hola'

# case 2:
$greeting = null;
echo $greeting ?? 'Hi There'; # outputs: 'Hi There'

# case 3:
unset($greeting);
echo $greeting ?? 'Hi There'; # outputs: 'Hi There'

上面的代码示例指出Null Coalescing operator以相同的方式处理不存在的变量和设置为NULL的变量。

Null Coalescing operator是对ternary operator的改进。看看下面的代码片段,比较两者:

<?php /* example: checking for the $_POST field that goes by the name of 'fullname'*/
# in ternary operator
echo "Welcome ", (isset($_POST['fullname']) && !is_null($_POST['fullname']) ? $_POST['fullname'] : 'Mr. Whosoever.'); # outputs: Welcome Mr. Whosoever.
# in null coalecing operator
echo "Welcome ", ($_POST['fullname'] ?? 'Mr. Whosoever.'); # outputs: Welcome Mr. Whosoever.

因此,两者之间的区别在于Null Coalescing operator运算符旨在比ternary operator更好地处理未定义的变量。鉴于ternary operatorif-else的缩写。

Null Coalescing operator并不是要替换ternary operator,但在上面示例中的某些用例中,它可以让您轻松编写干净的代码。

致谢:http://dwellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples

答案 12 :(得分:0)

使用$ _GET或$ _REQUEST之类的超全局变量时,您应该意识到它们可能是一个空字符串。 在这种情况下,这个例子

$username = $_GET['user'] ?? 'nobody';

将失败,因为$ username的值现在是一个空字符串。

因此,在使用$ _GET甚至$ _REQUEST时,应使用三元运算符,如下所示:

$username = (!empty($_GET['user'])?$_GET['user']:'nobody';

现在$ username的值像预期的那样为“ nobody”。