关于php 7:PHP三元运算符vs null合并运算符

PHP ternary operator vs null coalescing operator

有人能解释PHP中三元运算符速记(?:和空合并运算符(??之间的区别吗?

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

1
$a ?: $b

VS

1
$a ?? $b

当第一个参数为空时,它们基本上是相同的,只是当您有一个未定义的变量时,空合并不会输出一个E_NOTICE。php 7.0迁移文档有这样的说法:

The null coalescing operator (??) has been added as syntactic sugar
for the common case of needing to use a ternary in conjunction with
isset(). It returns its first operand if it exists and is not NULL;
otherwise it returns its second operand.

下面是一些示例代码来演示这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php

$a = null;

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

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

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

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

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

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

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

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

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

它的输出:

1
2
3
4
5
6
7
8
9
10
11
12
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。一旦它不再为空,那么您将得到不同的结果,即??运算符总是返回第一个参数,而?:速记则只在第一个参数是真的时才返回,这取决于php如何将事物类型转换为布尔值。

所以:

1
2
$a = false ?? 'f';
$b = false ?: 'g';

那么,$a等于false$b等于'g'


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

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

因此,你必须这样做:

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

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

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

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

您也可以这样做,并且将返回第一个定义的(set和not null值:

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

现在这是一个适当的合并操作符。


主要区别在于

  • 三元运算符表达式expr1 ?: expr3返回expr1,如果expr1的计算结果为但另一方面,空合并运算符表达式(expr1) ?? (expr2)如果expr1不是NULL,则评估为expr1

  • 三元的如果左侧值(expr1)不存在,但另一方面,空合并运算符(expr1) ?? (expr2)尤其不发出通知,如果左侧值(expr1)存在不存在,就像isset()一样。

  • 三元运算符是左关联的

    1
    ((true ? 'true' : false) ? 't' : 'f');

    空合并运算符是右关联的

    1
    ($a ?? ($b ?? $c));
  • 现在让我们通过示例来解释这两者之间的区别:

    三元运算符(?:)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $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);

    空合并运算符(??)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $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);

    这是解释'??'?:之间的区别和相似性的表格。

    enter image description here

    Special Note : null coalescing operator and ternary operator is an
    expression, and that it doesn't evaluate to a variable, but to the
    result of an expression. This is important to know if you want to
    return a variable by reference. The statement return $foo ?? $bar; and
    return $var == 42 ? $a : $b; in a return-by-reference function will
    therefore not work and a warning is issued.


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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
    • 这意味着??( !isset() || is_null() )相同。

    2。三元运算符-?:

    • ?:就像一扇大门,让anything falsy通过,包括NULL在内。
    • 0empty stringNULLfalse!isset()empty()。任何闻起来有问题的东西
    • 就像经典的三元运算符:echo ($x ? $x : false)
    • 注:?:将在未定义(unset!isset()变量上抛出PHP NOTICE

    三。医生,我什么时候用???:

    • 我只是开玩笑-我不是医生,这只是个解释
    • 我会用?:
      • 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
    2
    3
    4
    5
    6
    7
    8
    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

    此代码的源代码和信用

    这基本上是一个序列:

    1
    2
    3
    4
    5
    if( truthy ) {}
    else if(truthy ) {}
    else if(truthy ) {}
    ..
    else {}
  • 可以堆叠空coalese运算符…

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

    这是一系列:

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(!isset($_GET['name'])){
       if(isset($user_name) && !empty($user_name)){
          $name = $user_name;
       }else {
          $name = 'anonymous';
       }
    } else {
       $name = $_GET['name'];
    }

    对此:

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

    酷,对吧?-)


  • 当涉及到动态数据处理时,它们的行为都不同。

    如果变量为空(""),则空合并将把该变量视为真,而速记三元运算符则不会。这是需要考虑的问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    $a = NULL;
    $c = '';

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

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

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

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

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

    print $e ?: '2f';

    输出:

    1
    2
    3
    4
    5
    6
    7
    8
    1b
    2b

    2d
    1f

    Notice: Undefined variable: e in /in/ZBAa1 on line 21
    2f

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


    这两个词都是长句的简称。

    ?:$a ? $a : $b的缩写。如果$A的值为true,则此表达式的值将为$A。

    ??isset($a) ? $a : $b的缩写。如果设置了$A且不为空,则此表达式的值将为$A。

    当$A未定义或为空时,它们的用例会重叠。当$A未定义时,??将不会生成e_通知,但结果是相同的。当$A为空时,结果相同。


    向下滚动此链接并查看该部分,它提供了如下所示的比较示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?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';
    ?>

    但是,不建议将运算符链接起来,因为这样在以后读取代码时更难理解代码。

    The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.

    本质上,使用合并运算符将使其自动检查是否为空,这与三元运算符不同。


    使用???:似乎有利弊。使用?:的好处在于,它的计算结果为假、空,并且"相同"。问题在于,如果前面的参数为空,它将报告一个e_通知。对于??来说,赞成的是没有e-u通知,但反对的是,它的评估结果不为假,也不为空。在我的经验中,我看到人们开始交替使用空值和假值,但是他们最终会通过修改代码来与使用空值或假值保持一致,但不能同时使用两者。另一种选择是创造一个更为复杂的三元条件:(isset($something) or !$something) ? $something : $something_else

    下面是使用??运算符(同时使用null和false)的区别示例:

    1
    2
    3
    4
    5
    6
    7
    $false = null;
    $var = $false ??"true";
    echo $var ."---";//returns: true---

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

    然而,通过对三元运算符的详细说明,我们可以使一个假字符串或空字符串"表现得像一个空字符串,而不抛出e_通知:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $false = null;
    $var = (isset($false) or !$false) ? $false :"true";
    echo $var ."---";//returns: ---

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

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

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

    我个人认为,如果将来的PHP版本中包含另一个新的操作符::?,这将非常好,因为它取代了上述语法。IE:// $var = $false :?"true";该语法将计算null、false和"相等,并且不会抛出e-u通知…


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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.

    当使用诸如$u get或$u请求之类的超全局变量时,您应该注意它们可能是空字符串。在这个特殊情况下,这个例子

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

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

    因此,当使用$u get或甚至$u请求时,您应该使用三元运算符,而不是如下所示:

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

    现在$username的值如预期的"nobody"。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?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的改进。查看下面比较这两个代码段的代码段:

    1
    2
    3
    4
    5
    <?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://bellupper.io/post/6/php7-null-coalescing-operator-usage-and-examples